package com.salesmanager.web.init.data;

import com.salesmanager.core.business.catalog.category.model.Category;
import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
import com.salesmanager.core.business.catalog.category.service.CategoryService;
import com.salesmanager.core.business.catalog.product.model.Product;
import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationshipType;
import com.salesmanager.core.business.catalog.product.model.type.ProductType;
import com.salesmanager.core.business.catalog.product.service.ProductService;
import com.salesmanager.core.business.catalog.product.service.attribute.ProductAttributeService;
import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionService;
import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionValueService;
import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
import com.salesmanager.core.business.catalog.product.service.image.ProductImageService;
import com.salesmanager.core.business.catalog.product.service.manufacturer.ManufacturerService;
import com.salesmanager.core.business.catalog.product.service.price.ProductPriceService;
import com.salesmanager.core.business.catalog.product.service.relationship.ProductRelationshipService;
import com.salesmanager.core.business.catalog.product.service.type.ProductTypeService;
import com.salesmanager.core.business.common.model.Billing;
import com.salesmanager.core.business.common.model.Delivery;
import com.salesmanager.core.business.content.model.FileContentType;
import com.salesmanager.core.business.content.model.ImageContentFile;
import com.salesmanager.core.business.customer.model.Customer;
import com.salesmanager.core.business.customer.model.CustomerGender;
import com.salesmanager.core.business.customer.service.CustomerService;
import com.salesmanager.core.business.generic.exception.ServiceException;
import com.salesmanager.core.business.merchant.model.MerchantStore;
import com.salesmanager.core.business.merchant.service.MerchantStoreService;
import com.salesmanager.core.business.order.model.Order;
import com.salesmanager.core.business.order.model.OrderTotal;
import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
import com.salesmanager.core.business.order.model.orderproduct.OrderProductPrice;
import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
import com.salesmanager.core.business.order.service.OrderService;
import com.salesmanager.core.business.payments.model.PaymentType;
import com.salesmanager.core.business.reference.country.model.Country;
import com.salesmanager.core.business.reference.country.service.CountryService;
import com.salesmanager.core.business.reference.currency.model.Currency;
import com.salesmanager.core.business.reference.currency.service.CurrencyService;
import com.salesmanager.core.business.reference.language.model.Language;
import com.salesmanager.core.business.reference.language.service.LanguageService;
import com.salesmanager.core.business.reference.zone.model.Zone;
import com.salesmanager.core.business.reference.zone.service.ZoneService;
import com.salesmanager.core.business.user.model.Group;
import com.salesmanager.core.business.user.model.GroupType;
import com.salesmanager.core.business.user.service.GroupService;
import com.salesmanager.web.constants.Constants;
import com.salesmanager.web.utils.LocaleUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.PasswordEncoder;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class InitStoreWithQuantity implements InitData {
    private static final Logger LOGGER = LoggerFactory.getLogger(InitStoreData.class);

    @Autowired
    protected ProductService productService;


    @Autowired
    protected ProductPriceService productPriceService;

    @Autowired
    protected ProductAttributeService productAttributeService;

    @Autowired
    protected ProductOptionService productOptionService;

    @Autowired
    protected ProductOptionValueService productOptionValueService;

    @Autowired
    protected ProductAvailabilityService productAvailabilityService;

    @Autowired
    protected ProductImageService productImageService;

    @Autowired
    protected CategoryService categoryService;

    @Autowired
    protected MerchantStoreService merchantService;

    @Autowired
    protected ProductTypeService productTypeService;

    @Autowired
    protected LanguageService languageService;

    @Autowired
    protected CountryService countryService;

    @Autowired
    protected ZoneService zoneService;

    @Autowired
    protected CustomerService customerService;

    @Autowired
    protected ManufacturerService manufacturerService;

    @Autowired
    protected CurrencyService currencyService;

    @Autowired
    protected OrderService orderService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    protected GroupService groupService;

    @Autowired
    private ProductRelationshipService productRelationshipService;

    public int randInt(int max) {
        return ThreadLocalRandom.current().nextInt(max);
    }

    public void initInitialData() throws ServiceException {


        LOGGER.info("Starting the initialization of test data with quantities");
        Date date = new Date(System.currentTimeMillis());

        //2 languages by default
        Language en = languageService.getByCode("en");
        Language fr = languageService.getByCode("fr");

        Country canada = countryService.getByCode("CA");
        Zone zone = zoneService.getByCode("QC");

        //create a merchant
        MerchantStore store = merchantService.getMerchantStore(MerchantStore.DEFAULT_STORE);
        ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);


        //adding categories
        List<Category> categories = new ArrayList<>();
        String[] categorySubjects = new String[]{"ARTS",
                "BIOGRAPHIES",
                "BUSINESS",
                "CHILDREN",
                "COMPUTERS",
                "COOKING",
                "HEALTH",
                "HISTORY",
                "HOME",
                "HUMOR",
                "LITERATURE",
                "MYSTERY",
                "NON-FICTION",
                "PARENTING",
                "POLITICS",
                "REFERENCE",
                "RELIGION",
                "ROMANCE",
                "SELF-HELP",
                "SCIENCE-NATURE",
                "SCIENCE-FICTION",
                "SPORTS",
                "YOUTH",
                "TRAVEL"};
                //TODO redo with these categories


        Category book = new Category();
        book.setMerchantStore(store);
        book.setCode("computerbooks");
        book.setVisible(true);

        CategoryDescription bookEnglishDescription = new CategoryDescription();
        bookEnglishDescription.setName("Computer Books");
        bookEnglishDescription.setCategory(book);
        bookEnglishDescription.setLanguage(en);
        bookEnglishDescription.setSeUrl("computer-books");

        CategoryDescription bookFrenchDescription = new CategoryDescription();
        bookFrenchDescription.setName("Livres d'informatique");
        bookFrenchDescription.setCategory(book);
        bookFrenchDescription.setLanguage(fr);
        bookFrenchDescription.setSeUrl("livres-informatiques");

        List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
        descriptions.add(bookEnglishDescription);
        descriptions.add(bookFrenchDescription);

        book.setDescriptions(descriptions);

        categoryService.create(book);
        categories.add(book);

        Category novs = new Category();
        novs.setMerchantStore(store);
        novs.setCode("novels");
        novs.setVisible(false);

        CategoryDescription novsEnglishDescription = new CategoryDescription();
        novsEnglishDescription.setName("Novels");
        novsEnglishDescription.setCategory(novs);
        novsEnglishDescription.setLanguage(en);
        novsEnglishDescription.setSeUrl("novels");

        CategoryDescription novsFrenchDescription = new CategoryDescription();
        novsFrenchDescription.setName("Romans");
        novsFrenchDescription.setCategory(novs);
        novsFrenchDescription.setLanguage(fr);
        novsFrenchDescription.setSeUrl("romans");

        List<CategoryDescription> descriptions2 = new ArrayList<CategoryDescription>();
        descriptions2.add(novsEnglishDescription);
        descriptions2.add(novsFrenchDescription);

        novs.setDescriptions(descriptions2);

        categoryService.create(novs);
        categories.add(novs);

        Category tech = new Category();
        tech.setMerchantStore(store);
        tech.setCode("tech");

        CategoryDescription techEnglishDescription = new CategoryDescription();
        techEnglishDescription.setName("Technology");
        techEnglishDescription.setCategory(tech);
        techEnglishDescription.setLanguage(en);
        techEnglishDescription.setSeUrl("technology");

        CategoryDescription techFrenchDescription = new CategoryDescription();
        techFrenchDescription.setName("Technologie");
        techFrenchDescription.setCategory(tech);
        techFrenchDescription.setLanguage(fr);
        techFrenchDescription.setSeUrl("technologie");

        List<CategoryDescription> descriptions4 = new ArrayList<CategoryDescription>();
        descriptions4.add(techEnglishDescription);
        descriptions4.add(techFrenchDescription);

        tech.setDescriptions(descriptions4);

        tech.setParent(book);

        categoryService.create(tech);
        categoryService.addChild(book, tech);
        categories.add(tech);

        Category web = new Category();
        web.setMerchantStore(store);
        web.setCode("web");
        web.setVisible(true);

        CategoryDescription webEnglishDescription = new CategoryDescription();
        webEnglishDescription.setName("Web");
        webEnglishDescription.setCategory(web);
        webEnglishDescription.setLanguage(en);
        webEnglishDescription.setSeUrl("the-web");

        CategoryDescription webFrenchDescription = new CategoryDescription();
        webFrenchDescription.setName("Web");
        webFrenchDescription.setCategory(web);
        webFrenchDescription.setLanguage(fr);
        webFrenchDescription.setSeUrl("le-web");

        List<CategoryDescription> descriptions3 = new ArrayList<CategoryDescription>();
        descriptions3.add(webEnglishDescription);
        descriptions3.add(webFrenchDescription);

        web.setDescriptions(descriptions3);

        web.setParent(book);

        categoryService.create(web);
        categoryService.addChild(book, web);
        categories.add(web);


        Category fiction = new Category();
        fiction.setMerchantStore(store);
        fiction.setCode("fiction");
        fiction.setVisible(true);

        CategoryDescription fictionEnglishDescription = new CategoryDescription();
        fictionEnglishDescription.setName("Fiction");
        fictionEnglishDescription.setCategory(fiction);
        fictionEnglishDescription.setLanguage(en);
        fictionEnglishDescription.setSeUrl("fiction");

        CategoryDescription fictionFrenchDescription = new CategoryDescription();
        fictionFrenchDescription.setName("Sc Fiction");
        fictionFrenchDescription.setCategory(fiction);
        fictionFrenchDescription.setLanguage(fr);
        fictionFrenchDescription.setSeUrl("fiction");

        List<CategoryDescription> fictiondescriptions = new ArrayList<CategoryDescription>();
        fictiondescriptions.add(fictionEnglishDescription);
        fictiondescriptions.add(fictionFrenchDescription);

        fiction.setDescriptions(fictiondescriptions);

        fiction.setParent(novs);

        categoryService.create(fiction);
        categoryService.addChild(novs, fiction);
        categories.add(fiction);


        Category business = new Category();
        business.setMerchantStore(store);
        business.setCode("business");
        business.setVisible(true);

        CategoryDescription businessEnglishDescription = new CategoryDescription();
        businessEnglishDescription.setName("Business");
        businessEnglishDescription.setCategory(business);
        businessEnglishDescription.setLanguage(en);
        businessEnglishDescription.setSeUrl("business");

        CategoryDescription businessFrenchDescription = new CategoryDescription();
        businessFrenchDescription.setName("Affaires");
        businessFrenchDescription.setCategory(business);
        businessFrenchDescription.setLanguage(fr);
        businessFrenchDescription.setSeUrl("affaires");

        List<CategoryDescription> businessdescriptions = new ArrayList<CategoryDescription>();
        businessdescriptions.add(businessEnglishDescription);
        businessdescriptions.add(businessFrenchDescription);

        business.setDescriptions(businessdescriptions);


        categoryService.create(business);
        categories.add(business);


        Category cloud = new Category();
        cloud.setMerchantStore(store);
        cloud.setCode("cloud");
        cloud.setVisible(true);

        CategoryDescription cloudEnglishDescription = new CategoryDescription();
        cloudEnglishDescription.setName("Cloud computing");
        cloudEnglishDescription.setCategory(cloud);
        cloudEnglishDescription.setLanguage(en);
        cloudEnglishDescription.setSeUrl("cloud-computing");

        CategoryDescription cloudFrenchDescription = new CategoryDescription();
        cloudFrenchDescription.setName("Programmation pour le cloud");
        cloudFrenchDescription.setCategory(cloud);
        cloudFrenchDescription.setLanguage(fr);
        cloudFrenchDescription.setSeUrl("programmation-cloud");

        List<CategoryDescription> clouddescriptions = new ArrayList<CategoryDescription>();
        clouddescriptions.add(cloudEnglishDescription);
        clouddescriptions.add(cloudFrenchDescription);

        cloud.setDescriptions(clouddescriptions);

        cloud.setParent(tech);

        categoryService.create(cloud);
        categoryService.addChild(tech, cloud);
        categories.add(cloud);

        // Add products
        // ProductType generalType = productTypeService.

        //adding manufacturers
        List<Manufacturer> manufacturers = new ArrayList<>();
        for (int i = 0; i <= 500; i++) {
            Manufacturer manufacturer = new Manufacturer();
            manufacturer.setMerchantStore(store);
            manufacturer.setCode("manufacturer" + i);

            ManufacturerDescription manufacturerd = new ManufacturerDescription();
            manufacturerd.setLanguage(en);
            manufacturerd.setName("manufacturer" + i);
            manufacturerd.setManufacturer(manufacturer);
            manufacturer.getDescriptions().add(manufacturerd);

            manufacturerService.create(manufacturer);

            manufacturers.add(manufacturer);
        }

        //adding products
        List<Product> products = new ArrayList<>();
        for (int i = 0; i <= 2000; i++) {

            Product product = new Product();
            product.setProductHeight(new BigDecimal(randInt(10)));
            product.setProductLength(new BigDecimal(randInt(3)));
            product.setProductWidth(new BigDecimal(randInt(6)));
            product.setSku("TB" + i);
            product.setManufacturer(manufacturers.get(randInt(manufacturers.size())));
            product.setType(generalType);
            product.setMerchantStore(store);
            product.setProductShipeable(true);

            // Product description
            ProductDescription description = new ProductDescription();
            description.setName("Description" + i);
            description.setLanguage(en);
            description.setSeUrl("Description" + i);
            description.setProduct(product);

            product.getDescriptions().add(description);

            for (int j = 0; j <= randInt(3); j++) {
                product.getCategories().add(categories.get(randInt(categories.size())));
            }

            productService.create(product);

//            try {
//                InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("/demo/spring.png");
//                this.saveFile(inStream, "spring.png", product);
//            } catch (Exception e) {
//                LOGGER.error("Error while reading demo file spring.png", e);
//            }

            // Availability
            ProductAvailability availability = new ProductAvailability();
            availability.setProductDateAvailable(date);
            availability.setProductQuantity(randInt(100));
            availability.setRegion("*");
            availability.setProduct(product);// associate with product

            productAvailabilityService.create(availability);

            ProductPrice dprice = new ProductPrice();
            dprice.setDefaultPrice(true);
            dprice.setProductPriceAmount(new BigDecimal(randInt(100)));
            dprice.setProductAvailability(availability);

            ProductPriceDescription dpd = new ProductPriceDescription();
            dpd.setName("Base price");
            dpd.setProductPrice(dprice);
            dpd.setLanguage(en);

            dprice.getDescriptions().add(dpd);

            productPriceService.create(dprice);
            products.add(product);
        }


        //featured items
        for (int i = 0; i <= randInt(20); i++) {
            ProductRelationship relationship = new ProductRelationship();
            relationship.setActive(true);
            relationship.setCode(ProductRelationshipType.FEATURED_ITEM.name());
            relationship.setStore(store);
            relationship.setRelatedProduct(products.get(randInt(products.size())));
            productRelationshipService.saveOrUpdate(relationship);
        }

        //Create a customers (user name[nick] : shopizer password : password)
        List<Customer> customers = new ArrayList<>();
        for (int i = 0; i <= 400; i++) {
            Customer customer = new Customer();
            customer.setMerchantStore(store);
            customer.setEmailAddress("customer" + i + "@shopizer.com");
            customer.setGender(CustomerGender.M);
            customer.setAnonymous(false);
            customer.setCompany("customer" + i + " company");
            customer.setDateOfBirth(new Date());

            customer.setDefaultLanguage(en);
            customer.setNick("customer" + i);

            String password = passwordEncoder.encodePassword("customer" + i, null);
            customer.setPassword(password);

            List<Group> groups = groupService.listGroup(GroupType.CUSTOMER);


            for (Group group : groups) {
                if (group.getGroupName().equals(Constants.GROUP_CUSTOMER)) {
                    customer.getGroups().add(group);
                }
            }

            Delivery delivery = new Delivery();
            delivery.setAddress("customer" + i);
            delivery.setCity("customer" + i);
            delivery.setCountry(canada);
//		    delivery.setCountryCode(canada.getIsoCode());
            delivery.setFirstName("Customer" + i);
            delivery.setLastName("Customer" + i);
            delivery.setPostalCode("J4B-8J9" + i);
            delivery.setZone(zone);

            Billing billing = new Billing();
            billing.setAddress("Customer" + i);
            billing.setCity("Customer" + i);
            billing.setCompany("Customer" + i);
            billing.setCountry(canada);
//		    billing.setCountryCode(canada.getIsoCode());
            billing.setFirstName("Customer" + i);
            billing.setLastName("Customer" + i);
            billing.setPostalCode("J4B-8J9" + i);
            billing.setZone(zone);

            customer.setBilling(billing);
            customer.setDelivery(delivery);
            customerService.create(customer);
            customers.add(customer);

            Currency currency = currencyService.getByCode("CAD");

            OrderStatusHistory orderStatusHistory = new OrderStatusHistory();

            //create orders
            for (int k = 1; k <= randInt(2); k++) {

                Customer c = customers.get(randInt(customers.size()));
                Order order = new Order();
                order.setDatePurchased(new Date());
                order.setCurrency(currency);
                order.setLastModified(new Date());
                order.setBilling(c.getBilling());


                order.setLocale(LocaleUtils.getLocale(store));

                order.setCurrencyValue(new BigDecimal(0.98));//compared to based currency (not necessary)
                order.setCustomerId(c.getId());
                order.setBilling(c.getBilling());
                order.setDelivery(c.getDelivery());
                order.setCustomerEmailAddress("order" + i + "@shopizer.com");
                order.setDelivery(c.getDelivery());
                order.setIpAddress("order" + i);
                order.setMerchant(store);
                order.setOrderDateFinished(new Date());//committed date

                orderStatusHistory.setComments("We received your order");
                orderStatusHistory.setCustomerNotified(1);
                orderStatusHistory.setStatus(OrderStatus.values()[randInt(OrderStatus.values().length)]);
                orderStatusHistory.setDateAdded(new Date());
                orderStatusHistory.setOrder(order);
                order.getOrderHistory().add(orderStatusHistory);


                order.setPaymentType(PaymentType.values()[randInt(PaymentType.values().length)]);
                order.setPaymentModuleCode("method");
                order.setStatus(OrderStatus.values()[randInt(OrderStatus.values().length)]);
                order.setTotal(new BigDecimal(randInt(100)));


                //OrderProductDownload - Digital download
                OrderProductDownload orderProductDownload = new OrderProductDownload();
                orderProductDownload.setDownloadCount(1);
                orderProductDownload.setMaxdays(31);
                orderProductDownload.setOrderProductFilename("Your digital file name");

                //OrderProductPrice
                OrderProductPrice oproductprice = new OrderProductPrice();
                oproductprice.setDefaultPrice(true);
                oproductprice.setProductPrice(new BigDecimal(randInt(100)));
                oproductprice.setProductPriceCode("baseprice");
                oproductprice.setProductPriceName("Base Price");
                //oproductprice.setProductPriceSpecialAmount(new BigDecimal(13.99) );


                //OrderProduct
                OrderProduct oproduct = new OrderProduct();
                oproduct.getDownloads().add(orderProductDownload);
                oproduct.setOneTimeCharge(new BigDecimal(randInt(100)));
                oproduct.setOrder(order);
                oproduct.setProductName("Product name");
                oproduct.setProductQuantity(randInt(5));
                oproduct.setSku("TB" + i);
                oproduct.getPrices().add(oproductprice);

                oproductprice.setOrderProduct(oproduct);
                orderProductDownload.setOrderProduct(oproduct);
                order.getOrderProducts().add(oproduct);

                //OrderTotal
                OrderTotal subtotal = new OrderTotal();
                subtotal.setModule("summary");
                subtotal.setSortOrder(0);
                subtotal.setText("Summary");
                subtotal.setTitle("Summary");
                subtotal.setOrderTotalCode("subtotal");
                subtotal.setValue(new BigDecimal(randInt(100)));
                subtotal.setOrder(order);

                order.getOrderTotal().add(subtotal);

                OrderTotal tax = new OrderTotal();
                tax.setModule("tax");
                tax.setSortOrder(1);
                tax.setText("Tax");
                tax.setTitle("Tax");
                tax.setOrderTotalCode("tax");
                tax.setValue(new BigDecimal(randInt(5)));
                tax.setOrder(order);

                order.getOrderTotal().add(tax);

                OrderTotal total = new OrderTotal();
                total.setModule("total");
                total.setSortOrder(2);
                total.setText("Total");
                total.setTitle("Total");
                total.setOrderTotalCode("total");
                total.setValue(new BigDecimal(randInt(30)));
                total.setOrder(order);

                order.getOrderTotal().add(total);

                orderService.create(order);
            }
        }

    }

    private void saveFile(InputStream fis, String name, Product product) throws Exception {

        if (fis == null) {
            return;
        }

        final byte[] is = IOUtils.toByteArray(fis);
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(is);
        final ImageContentFile cmsContentImage = new ImageContentFile();
        cmsContentImage.setFileName(name);
        cmsContentImage.setFile(inputStream);
        cmsContentImage.setFileContentType(FileContentType.PRODUCT);


        ProductImage productImage = new ProductImage();
        productImage.setProductImage(name);
        productImage.setProduct(product);


        productImageService.addProductImage(product, productImage, cmsContentImage);


    }

}
