package com.huigou.topsun.product.application.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huigou.topsun.product.application.ProductApplication;
import com.huigou.topsun.product.domain.*;
import com.huigou.topsun.product.repository.*;
import com.huigou.topsun.util.EntityConvertUtil;
import com.huigou.topsun.util.PersistTool;
import com.huigou.uasp.bmp.common.application.BaseApplication;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// @RequiredArgsConstructor 通过构造方法注入同 ProductApplication(Class a) { this.a = a; }
/**
 * description 针对表【product(产品)】的数据库操作Service实现
 * @author 16508
 * @createDate 2023-11-22 10:24:31
 */
@Service
@RequiredArgsConstructor
public class ProductApplicationImpl extends BaseApplication implements ProductApplication {

    @PersistenceContext(unitName = "system")
    private EntityManager entityManager;

    private final PersistTool persist;

//    private final EntityManagerFactory entityManagerFactory;

    private final ObjectMapper objectMapper;
    private final  ProductRepository productRepository;
    private final ProductDetailRepository detailRepository;

    // 类型

    private final BrandRepository brandRepository;
    private final FactoryRepository factoryRepository;
    private final ColorRepository colorRepository;
    private final ProductCategoryRepository categoryRepository;

    // 详细信息

    private final ProductTypesetConfRepository typesetConfRepository;
    private final ProductLookedRepository lookedRepository;
    private final ProductPublishedConfRepository publishedConfRepository;
    private final ProductLossRepository lossRepository;
    private final ProductMaterialRepository materialRepository;

    private final ProductFaceRepository faceRepository;
    private final ProductFaceColorRepository faceColorRepository;
    private final ProductTechnologyRepository technologyRepository;
    private final ProductProcessRepository processRepository;

    @Override
    public ArrayList<Map<String, Object>> findProductPage(int page, int size) {
        ArrayList<Product> productPage = (ArrayList<Product>) productRepository.findAll();
        return objectMapper.convertValue(productPage, new TypeReference<ArrayList<Map<String, Object>>>() {});
    }

    /**
     * description 查询产品所有详细信息
     * @param product 产品ID
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author qinzhenguan
     * @createDate 2023/11/29 13:19
     */
    @Override
    public Map<String, Object> queryDetailAll(Product product) {
        Map<String, Object> resultMap = new HashMap<>(200);
        BigDecimal productId =  product.getProductId();
        ProductDetail productDetail = detailRepository.findByProductId(productId);
        ProductTechnology productTechnology = technologyRepository.findByProductId(productId);

        // ---------------------------------  类别查询 ---------------------------------
        ArrayList<Brand> brands = (ArrayList<Brand>)brandRepository.findAll();
        ArrayList<Factory> factorys = (ArrayList<Factory>)factoryRepository.findAll();
        ArrayList<Color> colors = (ArrayList<Color>)colorRepository.findAll();
        ArrayList<ProductCategory> categorys = (ArrayList<ProductCategory>)categoryRepository.findAll();

        // ---------------------------------  详情查询 ---------------------------------

        ArrayList<ProductMaterial> material = (ArrayList<ProductMaterial>) materialRepository.findByProductId(productId);
        ArrayList<ProductLoss> loss = (ArrayList<ProductLoss>) lossRepository.findByProductId(productId);
        Set<Object> entitys = new HashSet<>();
        entitys.add(typesetConfRepository.findByProductId(productId));
        entitys.add(lookedRepository.findByProductId(productId));
        entitys.add(publishedConfRepository.findByProductId(productId));
        entitys.add(productDetail);
        entitys.add(productTechnology == null ? new ProductTechnology() : productTechnology);
        entitys.add(product);
        entitys.add(material);

        Map<String, Object> assemble = EntityConvertUtil.assembleResultOfForm(entitys);
        resultMap.put("rawData", assemble);
        assemble.put("productLoss", loss);

        // ---------------------------------  版面查询 ---------------------------------
        if(productDetail != null) {
            ArrayList<ProductFace> frontFaces = new ArrayList<>();
            if(productDetail.getBackProductFaceId() != null) {
                ProductFace frontFace = faceRepository.findByProductFaceId(productDetail.getRightProductFaceId());
                frontFace.setBack(false);
                ArrayList <ProductFaceColor> fronColors =
                        (ArrayList<ProductFaceColor>) faceColorRepository.findByProductFaceId(productDetail.getRightProductFaceId());
                frontFaces.add(frontFace);
                assemble.put("fronColors", fronColors == null ? new ArrayList<>() : fronColors);
            } else {
                ProductFaceColor fc = new ProductFaceColor();
                fc.setProductFaceColorId("111");
                fc.setColorId("1");
                ArrayList<ProductFaceColor> fronColors =  new ArrayList<>();
                fronColors.add(fc);
                assemble.put("fronColors", fronColors);
            }
            if(productDetail.getBackProductFaceId() != null) {
                ProductFace backFace = faceRepository.findByProductFaceId(productDetail.getBackProductFaceId());
                backFace.setBack(true);
                ArrayList <ProductFaceColor> backColors =
                        (ArrayList<ProductFaceColor>) faceColorRepository.findByProductFaceId(productDetail.getBackProductFaceId());
                frontFaces.add(backFace);
                assemble.put("backColors", backColors == null ? new ArrayList<>() : backColors);
            } else {
                ProductFaceColor fc = new ProductFaceColor();
                fc.setProductFaceColorId("111");
                fc.setColorId("1");
                ArrayList<ProductFaceColor> fronColors =  new ArrayList<>();
                fronColors.add(fc);
                assemble.put("backColors", fronColors);
            }
            assemble.put("frontFaces", frontFaces);

        }

        // ---------------------------------  工序查询 ---------------------------------
        if(productTechnology != null) {
            if(productTechnology.getProductTechnologyId() != null) {
                ArrayList<ProductProcess> processesed =
                        (ArrayList<ProductProcess>) processRepository.findByProductTechnologyId(productTechnology.getProductTechnologyId());
                assemble.put("processed", processesed == null ? new ArrayList<>() : processesed);
            } else {
                ProductProcess fc = new ProductProcess();
                fc.setProductProcessId("111");
                fc.setProductProcessId("1");
                ArrayList<ProductProcess> processed =  new ArrayList<>();
                processed.add(fc);
                assemble.put("processed", processed);
            }
        }

        HashMap<String, Object> listMaps = new HashMap<>(100);
        listMaps.put("selectedBrand", objectMapper.convertValue(brands, List.class));
        listMaps.put("selectedFactory", objectMapper.convertValue(factorys, List.class));
        listMaps.put("selectedColor", objectMapper.convertValue(colors, List.class));
        listMaps.put("selectedCategory", objectMapper.convertValue(categorys, List.class));
        resultMap.put("listMaps", listMaps);
        return resultMap;
    }

    /***
     * description  保存所有产品关联信息
     * @param newData   发生变更的所有数据实体，传入该方法所有数据都将持久化。
     * @return java.util.HashMap<java.lang.String, java.lang.Object>
     * @author qinzhenguan
     * @createDate 2023/12/26 17:05
     */
    @Override
    @Transactional(transactionManager="transactionManager")
    public HashMap<String, Object> saveOrUpdataOnAllDetail(HashMap<String, Object> newData) {
        Product product = objectMapper.convertValue(newData.get("Product"), Product.class);
        ProductDetail productDetail = objectMapper.convertValue(newData.get("ProductDetail"), ProductDetail.class);
        ProductLooked productLooked = objectMapper.convertValue(newData.get("ProductLooked"), ProductLooked.class);
        ProductFace productFace = objectMapper.convertValue(newData.get("frontFace"), ProductFace.class);
        ProductTechnology productTechnology = objectMapper.convertValue(newData.get("ProductTechnology"),
                ProductTechnology.class);
        ProductPublishedConf productPublishedConf = objectMapper.convertValue(newData.get("ProductPublishedConf"),
                ProductPublishedConf.class);
        // ---------------------------------  反序列化 List (可在此加入业务逻辑) ---------------------------------
        HashMap<String, Object> faceColors = convertToFaceColors(uncheckedCast(newData.get("fronColors")));
        HashMap<String, Object> backColors = convertToFaceColors(uncheckedCast(newData.get("backColors")));
        HashMap<String, Object> processeds = convertToProcesseds(uncheckedCast(newData.get("processed")));
        HashMap<String, Object> lossed = convertToLossed(uncheckedCast(newData.get("productLoss")));

        List<Map<String, Object>> maps = Stream.of(faceColors, backColors, processeds, lossed).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, Object> mergedMap = maps.stream()
                .flatMap(map -> map.entrySet().stream())
                .filter(entry -> entry.getValue() != null)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (listA, listB) -> {
                    ArrayList<Map<String, Object>> mergedList = new ArrayList<>(uncheckedCast(listA));
                    mergedList.addAll(uncheckedCast(listB));
                    return mergedList;
                }));

        Set<Object> entitys = new HashSet<>();
        entitys.add(mergedMap);
        entitys.add(product);
        entitys.add(productDetail);
        entitys.add(productFace);
        entitys.add(productLooked);
        entitys.add(productTechnology);
        entitys.add(productPublishedConf);
        persist.persistEntitys(entitys);

        TypedQuery<Product> query = entityManager.createQuery("SELECT s FROM Product s", Product.class);
        List<Product> products = query.getResultList();

        entityManager.flush();

//        String str = null;
//        str.length();

        HashMap<String, Object>  map = new HashMap<>(5);
        map.put("save", "ok");

        return map;
    }

    @Override
    public HashMap<String, Object> queryProductList() {
        String sql = "SELECT\n" +
                "\tt.product_id,\n" +
                "\tt.product_category_id,\n" +
                "\tt.product_unit,\n" +
                "\tt.is_only_code,\n" +
                "\tt.brand_name,\n" +
                "\tpc.dispatch_multiple,\n" +
                "\tpc.row_num,\n" +
                "\tpt.product_technology_name\n" +
                "FROM\n" +
                "\tproduct t\n" +
                "\tLEFT JOIN product_published_conf pc ON t.product_id = pc.product_id\n" +
                "\tLEFT JOIN product_technology pt ON t.product_id = pt.product_id";
        ArrayList<Map<String, Object>> list = (ArrayList<Map<String, Object>>) this.sqlExecutorDao.queryToListMap(sql);
        HashMap<String, Object> map = new HashMap<>(3);
        map.put("productList", list);
        return map;
    }

    @SuppressWarnings("unchecked")
    public static <T> T uncheckedCast(Object obj) {
        if(obj != null) {
            return (T) obj;
        }
        return null;
    }

    public HashMap<String, Object> convertToFaceColors(Map<String, ArrayList<Map<String, Object>>> map) {
        if(map == null) {
            return null;
        }
        HashMap<String, Object> retult = new HashMap<>(5);
        retult.put("add", convertColor(map.get("add")));
        retult.put("up", convertColor(map.get("up")));
        retult.put("del", convertColor(map.get("del")));
        return retult;
    }

    public ArrayList<ProductFaceColor> convertColor(ArrayList<Map<String, Object>> list) {
        if(list.size() == 0) {
            return null;
        }
        return  objectMapper.convertValue(list, new TypeReference<ArrayList<ProductFaceColor>>() {});
    }

    private HashMap<String, Object> convertToProcesseds(Map<String, ArrayList<Map<String, Object>>> map) {
        if(map == null) {
            return null;
        }
        HashMap<String, Object> retult = new HashMap<>(5);
        retult.put("add", convertProcessed(map.get("add")));
        retult.put("up", convertProcessed(map.get("up")));
        retult.put("del", convertProcessed(map.get("del")));
        return retult;
    }

    public ArrayList<ProductProcess> convertProcessed(ArrayList<Map<String, Object>> list) {
        if(list.size() == 0) {
            return null;
        }
        return  objectMapper.convertValue(list, new TypeReference<ArrayList<ProductProcess>>() {});
    }

    private HashMap<String, Object> convertToLossed(Map<String, ArrayList<Map<String, Object>>> map) {
        if(map == null) {
            return null;
        }
        HashMap<String, Object> retult = new HashMap<>(5);
        retult.put("add", convertLossed(map.get("add")));
        retult.put("up", convertLossed(map.get("up")));
        retult.put("del", convertLossed(map.get("del")));
        return retult;
    }

    public ArrayList<ProductLoss> convertLossed(ArrayList<Map<String, Object>> list) {
        if(list.size() == 0) {
            return null;
        }
        return  objectMapper.convertValue(list, new TypeReference<ArrayList<ProductLoss>>() {});
    }



}

//        resultMap.put("selectedBrand", convertToMap(Brand.class, "brandName", "brandId", brands));
//        resultMap.put("selectedFactory", convertToMap(Factory.class, "factoryName", "factoryId", factorys));
//        resultMap.put("selectedColor", convertToMap(Color.class, "colorName", "colorId", colors));
//        resultMap.put("selectedCategory", convertToMap(ProductCategory.class, "productCategoryId",
//                "productCategoryName", categorys));


//    public ArrayList<Map<String, Object>> findProductPage(int page, int size) {
////        PageRequest pageRequest = new PageRequest(page, size);
////        Page<Product> productPage = productRepository.findAll(pageRequest);
////        mapList.getContent().stream().map(Product::toString).forEach(System.out::println);
//        ArrayList<Product> productPage = (ArrayList<Product>) productRepository.findAll();
//
////        convert = mapList.stream().collect(Collectors.toMap(index -> index, Function.identity(),
////                (oldV, newV) -> oldV));
//        return objectMapper.convertValue(productPage, new TypeReference<ArrayList<Map<String, Object>>>() {});
//    }
//


//        if(product != null) {
//            BigDecimal id = product.getProductId();
//            if(id == null) {
//                product.setProductId(String.valueOf(Snowflake.nextId()));
//                entityManager.persist(product);
//            }
//            entityManager.merge(product);
//        }
//        if(productDetail != null) {
//            BigDecimal id = productDetail.getProductDetailId();
//            if(id == null) {
//                productDetail.setProductDetailId(String.valueOf(Snowflake.nextId()));
//                entityManager.persist(productDetail);
//            }
//            entityManager.merge(productDetail);
//        }
//        if(productLooked != null) {
//            BigDecimal id = productLooked.getProductLookedId();
//            if(id == null) {
//                productLooked.setProductLookedId(String.valueOf(Snowflake.nextId()));
//                entityManager.persist(productLooked);
//            }
//            entityManager.merge(productLooked);
//        }
