package com.fjhx.item.service.product.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.file.entity.FileInfo;
import com.fjhx.file.entity.FileInfoSelectDto;
import com.fjhx.file.entity.FileInfoVo;
import com.fjhx.file.mapper.FileInfoMapper;
import com.fjhx.file.service.FileInfoService;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.item.ItemService;
import com.fjhx.item.entity.product.dto.ProductInfoDto;
import com.fjhx.item.entity.product.dto.ProductInfoSelectDto;
import com.fjhx.item.entity.product.po.ProductClassify;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.entity.product.po.ProductInfoEhsdExcel;
import com.fjhx.item.entity.product.po.ProductInfoEhsdJson;
import com.fjhx.item.entity.product.vo.ProductInfoVo;
import com.fjhx.item.mapper.product.ProductInfoMapper;
import com.fjhx.item.service.product.ProductClassifyService;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.item.util.CodeEnum;
import com.fjhx.item.util.excel.util.ExcelUtil;
import com.fjhx.tenant.entity.dict.dto.DictTenantDataSelectDto;
import com.fjhx.tenant.entity.dict.po.DictTenantData;
import com.fjhx.tenant.entity.dict.vo.DictTenantDataVo;
import com.fjhx.tenant.service.dict.DictTenantDataService;
import com.fjhx.tenant.utils.DictUtils;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.utils.UserUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 产品库 服务实现类
 * </p>
 *
 * @author zlj
 * @since 2023-03-17
 */
@DS(SourceConstant.ITEM)
@Service
public class ProductInfoServiceImpl extends ServiceImpl<ProductInfoMapper, ProductInfo> implements ProductInfoService {

    @Autowired
    private ProductClassifyService productClassifyService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private DictTenantDataService dictTenantDataService;
    @Autowired
    private FileInfoService fileInfoService;
    @Autowired
    private ItemService itemService;

    @Override
    public Page<ProductInfoVo> getPage(ProductInfoSelectDto dto) {
        IWrapper<ProductInfo> wrapper = getWrapper();
        wrapper.eq("pi", ProductInfo::getType, dto.getType());
        wrapper.eq("pi", ProductInfo::getDefinition, dto.getDefinition());

        if (dto.getProductClassifyId() != null) {
            List<Long> childIdList = productClassifyService.getChildIdList(dto.getProductClassifyId());
            wrapper.in("pi", ProductInfo::getProductClassifyId, childIdList);
        }

        wrapper.like("pi", ProductInfo::getName, dto.getName());
        wrapper.like("pi", ProductInfo::getCustomCode, dto.getCustomCode());
        wrapper.like("pi", ProductInfo::getBarCode, dto.getBarCode());
        wrapper.like("json_unquote(standard_json->'$.englishName')", dto.getEnglishName());
        wrapper.like("json_unquote(standard_json->'$.customsCode')", dto.getCustomsCode());
        wrapper.keyword(dto.getKeyword(),
                new SqlField("pi", ProductInfo::getName),
                new SqlField("pi", ProductInfo::getCode),
                new SqlField("pi", ProductInfo::getCustomCode),
                new SqlField("pi", ProductInfo::getSpec),
                //材质面料过滤
                new SqlField("json_unquote(pi.victoriatourist_json -> '$.materialQuality')")
        );
        //计算并根据生命周期过滤
        wrapper.eq("IF(DATEDIFF(now(),pi.create_time)> json_unquote( victoriatourist_json -> '$.growUpDay' ),3,IF( DATEDIFF(now(),pi.create_time)> json_unquote( victoriatourist_json -> '$.newProductsDay' ), 2, 1 ))", dto.getLifeCycle());
        //过滤组合产品
        wrapper.eq("json_unquote( victoriatourist_json -> '$.combination' )", dto.getCombination());

        //根据id倒序名称规格升序
        wrapper.orderByDesc("pi", ProductInfo::getId);
        wrapper.orderByAsc("pi", ProductInfo::getName);
        wrapper.orderByAsc("pi", ProductInfo::getSpec);

        //是否绑定工艺过滤
        if (ObjectUtil.isNotEmpty(dto.getIsTechnology())) {
            if (Objects.equals(0, dto.getIsTechnology())) {
                wrapper.isNull("aps.id");
            } else {
                wrapper.isNotNull("aps.id");
            }
        }

        wrapper.groupBy("pi.id");

        Page<ProductInfoVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);

        List<ProductInfoVo> records = page.getRecords();

        if (records.size() == 0) {
            return page;
        }

        List<ProductClassify> productClassifyList = productClassifyService.list();
        Map<Long, ProductClassify> productClassifyMap = productClassifyList.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));

        for (ProductInfoVo record : records) {
            Long productClassifyId = record.getProductClassifyId();
            ProductClassify productClassify = productClassifyMap.get(productClassifyId);
            if (productClassify == null) {
                continue;
            }

            record.setClassifyName(productClassify.getName());

            List<String> classifyNameGroup = new ArrayList<>();

            while (productClassify != null) {
                classifyNameGroup.add(0, productClassify.getName());
                productClassify = productClassifyMap.get(productClassify.getParentId());
            }
            record.setClassifyNameGroup(classifyNameGroup);

        }

        return page;
    }


    @Override
    public Page<ProductInfoVo> getPageByWdly(ProductInfoSelectDto dto) {
        Page<ProductInfoVo> page = getPage(dto);
        List<ProductInfoVo> records = page.getRecords();
        //赋值维多利亚扩展部门名称
        List<Long> ids = new ArrayList<>();
        for (ProductInfoVo record : records) {
            String victoriatouristJson = record.getVictoriatouristJson();
            if (ObjectUtil.isNotEmpty(victoriatouristJson)) {
                JSONObject json = JSONObject.parseObject(victoriatouristJson);
                ids.add(json.getLong("deptId"));
            }
        }
        if (ObjectUtil.isEmpty(ids)) {
            return page;
        }

        IWrapper<SysDept> wrapper1 = IWrapper.getWrapper();
        wrapper1.in(SysDept::getDeptId, ids);
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        List<SysDept> sysDepts = sysDeptService.list(wrapper1);
        DynamicDataSourceContextHolder.poll();
        Map<Long, String> sysDeptMap = sysDepts.stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName));

        for (ProductInfoVo record : records) {
            String victoriatouristJson = record.getVictoriatouristJson();

            if (ObjectUtil.isEmpty(victoriatouristJson)) {
                continue;
            }

            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            json.put("deptName", sysDeptMap.get(json.getLong("deptId")));

            //生命周期计算(在sql里面计算了) 当前时间-创建时间=的天数>growUpDay成熟期，>newProductsDay就是成长期，要不然就是新品期
            json.put("lifeCycle", record.getLifeCycle());

            //将部门id转为字符串(帮助解决前端问题)
            json.put("deptId", json.getString("deptId"));

            record.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }

        return page;
    }

    @Override
    public Page<ProductInfoVo> getCombinationPage(ProductInfoSelectDto dto) {
        dto.setCombination(1);
        Page<ProductInfoVo> page = getPageByWdly(dto);
        return page;
    }

    @Override
    public Page<ProductInfoVo> getCustomerProductList(ProductInfoSelectDto dto) {
        IWrapper<ProductInfo> wrapper = getWrapper();
        wrapper.eq("json_unquote(pi.ehsd_json -> '$.type')", 2);//客户产品
        return getPageByEhsd(dto, wrapper);
    }

    @Override
    public Page<ProductInfoVo> getConditionProductList(ProductInfoSelectDto dto) {
        IWrapper<ProductInfo> wrapper = getWrapper();
        wrapper.eq("json_unquote(pi.ehsd_json -> '$.type')", 1);//公司产品
        return getPageByEhsd(dto, wrapper);
    }

    /**
     * 尔泓产品库分页公共代码
     */
    public Page<ProductInfoVo> getPageByEhsd(ProductInfoSelectDto dto, IWrapper<ProductInfo> wrapper) {
        //根据产品名称/产品编号过滤
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            wrapper.and(q -> q.like("pi", ProductInfo::getName, dto.getKeyword())
                    .or().like("json_unquote(pi.ehsd_json -> '$.nameEnglish')", dto.getKeyword())
                    .or().like("pi", ProductInfo::getCode, dto.getKeyword())//产品编号
                    .or().like("c.name", dto.getKeyword()));//客户名称
        }
        //根据客户id过滤
        wrapper.eq("c.id", dto.getCustomerId());
        //根据产品分类id过滤
        wrapper.eq("pi", ProductInfo::getProductClassifyId, dto.getProductClassifyId());
        wrapper.orderByDesc("pi", ProductInfo::getCreateTime);

        Page<ProductInfoVo> page = baseMapper.getCustomerProductList(dto.getPage(), wrapper);
        List<ProductInfoVo> records = page.getRecords();
        //赋值客户名称
        List<Long> customerIds = new ArrayList<>();
        for (ProductInfoVo record : records) {
            ProductInfoEhsdJson productInfoEhsdJson = JSONObject.parseObject(record.getEhsdJson(), ProductInfoEhsdJson.class);
            customerIds.add(Long.parseLong(productInfoEhsdJson.getCustomerId()));
        }
        if (ObjectUtil.isNotEmpty(customerIds)) {
            Map<Long, String> customerMap = customerService.mapKV(Customer::getId, Customer::getName, q -> q.in(Customer::getId, customerIds));
            for (ProductInfoVo record : records) {
                ProductInfoEhsdJson productInfoEhsdJson = JSONObject.parseObject(record.getEhsdJson(), ProductInfoEhsdJson.class);
                String customerName = customerMap.get(Long.parseLong(productInfoEhsdJson.getCustomerId()));
                productInfoEhsdJson.setCustomerName(customerName);
                record.setEhsdJson(JSONObject.toJSONString(productInfoEhsdJson, JSONWriter.Feature.WriteLongAsString));
            }
        }
        //赋值创建人名称
        UserUtil.assignmentNickName(page.getRecords(), ProductInfo::getCreateUser, ProductInfoVo::setCreateUserName);
        return page;
    }

    @Override
    public ProductInfoVo detail(Long id) {
        ProductInfo productInfo = this.getById(id);
        ProductInfoVo result = BeanUtil.toBean(productInfo, ProductInfoVo.class);
        //赋值分类名称
        ProductClassify productClassify = productClassifyService.getById(result.getProductClassifyId());
        if (ObjectUtil.isNotEmpty(productClassify)) {
            result.setProductClassifyName(productClassify.getName());
        }
        //赋值 单位，物料类型 字典
        Integer definition = result.getDefinition();
        Map<String, String> materialUnitMap = DictUtils.getDictMap(definition == 1 ? "unit" : "material_unit");
        Map<String, String> materialTypeMap = DictUtils.getDictMap(definition == 1 ? "product_type" : "material_type");
        result.setTypeName(materialTypeMap.get(result.getType()));
        result.setUnitName(materialUnitMap.get(result.getUnit()));
        //赋值产品图片
        FileInfoSelectDto dto = new FileInfoSelectDto();
        dto.setBusinessIdList(Arrays.asList(result.getId()));
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        Map<Long, List<FileInfoVo>> fileInfoMap = fileInfoService.getList(dto);
        DynamicDataSourceContextHolder.poll();
        result.setFileList(fileInfoMap.get(result.getId()));
        //赋值库存
        BigDecimal stockQuantity = itemService.getStockQuantity(result.getId());
        result.setStockQuantity(stockQuantity);
        return result;
    }

    @Override
    public ProductInfoVo detailByWdly(Long id) {
        ProductInfoVo result = detail(id);
        //赋值维多利亚组合产品信息
        JSONObject json = JSONObject.parseObject(result.getVictoriatouristJson());
        List<Long> ids = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(json) && ObjectUtil.isNotEmpty(json.getJSONArray("productCombinationList"))) {
            JSONArray productCombinationList = json.getJSONArray("productCombinationList");
            for (int i = 0; i < productCombinationList.size(); i++) {
                JSONObject item = productCombinationList.getJSONObject(i);
                ids.add(item.getLong("linkProductId"));
            }
            if (ObjectUtil.isNotEmpty(ids)) {
                List<ProductInfo> productInfoList = this.listByIds(ids);
                Map<Long, ProductInfo> productInfoMap = productInfoList.stream().collect(Collectors.toMap(ProductInfo::getId, Function.identity()));
                JSONArray jsonArray = new JSONArray();
                for (int i = 0; i < productCombinationList.size(); i++) {
                    JSONObject item = productCombinationList.getJSONObject(i);
                    ProductInfo productInfo1 = productInfoMap.get(item.getLong("linkProductId"));
                    if (ObjectUtil.isNotEmpty(productInfo1)) {
                        item.put("code", productInfo1.getCode());
                        item.put("customCode", productInfo1.getCustomCode());
                        item.put("name", productInfo1.getName());
                    }
                    jsonArray.add(item);
                }
                json.put("productCombinationList", jsonArray);
                result.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
            }
        }
        return result;
    }

    @DSTransactional
    @Override
    public void add(ProductInfoDto productInfoDto) {
        // 赋值产品编号
        productInfoDto.setCode(CodeEnum.PRODUCT.getCode());
        //检查【产品名称】和【规格型号】不能同时重复，但可以单项重复。
        long nameAndSpecCount = this.count(q -> q
                .eq(ProductInfo::getName, productInfoDto.getName())
                .eq(ProductInfo::getSpec, productInfoDto.getSpec())
        );
        if (nameAndSpecCount != 0) {
            throw new ServiceException("同名称同规格的产品已存在");
        }
        // 排除不为空的自定义编码重复
        long count = this.count(q -> q.eq(ProductInfo::getCustomCode, productInfoDto.getCustomCode()).ne(ProductInfo::getCustomCode, ""));
        if (count != 0) {
            throw new ServiceException("产品自定义编码重复");
        }
        // 排除不为空的条码编号重复
        long count1 = this.count(q -> q.eq(ProductInfo::getBarCode, productInfoDto.getBarCode()).ne(ProductInfo::getBarCode, ""));
        if (count1 != 0) {
            throw new ServiceException("产品条码编码重复");
        }


        this.save(productInfoDto);
        ObsFileUtil.saveFile(productInfoDto.getFileList(), productInfoDto.getId());
    }

    @DSTransactional
    @Override
    public void addByEhsd(ProductInfoDto productInfoDto) {
        //赋值初始状态
        ProductInfoEhsdJson productInfoEhsdJson = JSONObject.parseObject(productInfoDto.getEhsdJson(), ProductInfoEhsdJson.class);
        if (ObjectUtil.isEmpty(productInfoEhsdJson.getCustomerId())) {
            //如果客户id为空就赋值为0 公司产品
            productInfoEhsdJson.setCustomerId("0");
            productInfoEhsdJson.setType("1");//默认公司产品
        }
        productInfoDto.setEhsdJson(JSONObject.toJSONString(productInfoEhsdJson, JSONWriter.Feature.WriteLongAsString));

        // 赋值产品编号
        productInfoDto.setCode(CodeEnum.PRODUCT.getCode());
        // 排除名称重复
        this.nameDuplication(ProductInfo::getName, productInfoDto.getName(), "产品名称重复");
        this.save(productInfoDto);
        //附件列表
        ObsFileUtil.saveFile(productInfoDto.getFileList(), productInfoDto.getId());
    }

    @DSTransactional
    @Override
    public void editByEhsd(ProductInfoDto productInfoDto) {
        ProductInfoEhsdJson newProductInfoEhsdJson = JSONObject.parseObject(productInfoDto.getEhsdJson(), ProductInfoEhsdJson.class);
        //只允许修改以下字段 销售指导价、成本价、净重、图片、备注
        ProductInfo productInfo = getById(productInfoDto.getId());
        if (ObjectUtil.isEmpty(productInfo)) {
            throw new ServiceException("无法查询到改产品的产品信息,产品id" + productInfoDto.getId());
        }
        ProductInfoEhsdJson productInfoEhsdJson = JSONObject.parseObject(productInfo.getEhsdJson(), ProductInfoEhsdJson.class);
        productInfoEhsdJson.setPrice(newProductInfoEhsdJson.getPrice());//销售指导价
        productInfoEhsdJson.setCostPrice(newProductInfoEhsdJson.getCostPrice());//成本价
        productInfoEhsdJson.setNetWeight(newProductInfoEhsdJson.getNetWeight());//净重
        productInfo.setRemark(productInfoDto.getRemark());//备注
        productInfo.setEhsdJson(JSONObject.toJSONString(productInfoEhsdJson, JSONWriter.Feature.WriteLongAsString));
        this.updateById(productInfo);
        //修改图片
        ObsFileUtil.editFile(productInfoDto.getFileList(), productInfoDto.getId());
    }

    @Override
    public ProductInfoVo detailByEhsd(Long id) {
        ProductInfo ProductInfo = this.getById(id);
        ProductInfoVo result = BeanUtil.toBean(ProductInfo, ProductInfoVo.class);

        ProductInfoEhsdJson productInfoEhsdJson = JSONObject.parseObject(result.getEhsdJson(), ProductInfoEhsdJson.class);
        //判断客户id不为空
        if (ObjectUtil.isNotEmpty(productInfoEhsdJson) && ObjectUtil.isNotEmpty(productInfoEhsdJson.getCustomerId())) {
            //赋值客户名称
            Customer customer = customerService.getById(productInfoEhsdJson.getCustomerId());
            if (ObjectUtil.isNotEmpty(customer)) {
                productInfoEhsdJson.setCustomerName(customer.getName());
                result.setEhsdJson(JSONObject.toJSONString(productInfoEhsdJson, JSONWriter.Feature.WriteLongAsString));
            }
        }
        //赋值创建人名称
        UserUtil.assignmentNickName(Arrays.asList(result), ProductInfoVo::getCreateUser, ProductInfoVo::setCreateUserName);
        return result;
    }

    @DSTransactional
    @Override
    public void excelImportByEhsd(MultipartFile file) {
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        Map<String, String> unitMap = dictTenantDataService.mapKV(DictTenantData::getDictValue,
                DictTenantData::getDictKey, q -> q.eq(DictTenantData::getDictCode, "unit"));
        Map<String, String> innerPackMethodMap = dictTenantDataService.mapKV(DictTenantData::getDictValue,
                DictTenantData::getDictKey, q -> q.eq(DictTenantData::getDictCode, "inner_packaging_method_ehsd"));
        Map<String, String> outsidePackMethodMap = dictTenantDataService.mapKV(DictTenantData::getDictValue,
                DictTenantData::getDictKey, q -> q.eq(DictTenantData::getDictCode, "outside_packaging_method_ehsd"));
        DynamicDataSourceContextHolder.poll();

        List<ProductInfoEhsdExcel> read = ExcelUtil.read(file, ProductInfoEhsdExcel.class);
        List<ProductInfo> productInfoList = new ArrayList<>();
        for (ProductInfoEhsdExcel productInfoEhsdExcel : read) {
            ProductInfo productInfo = BeanUtil.copyProperties(productInfoEhsdExcel, ProductInfo.class);
            // 赋值产品编号
            productInfo.setCode(CodeEnum.PRODUCT.getCode());
            // 排除名称重复
            this.nameDuplication(ProductInfo::getName, productInfo.getName(), "产品名称重复");

            //产品分类名称转id
            ProductClassify productClassify = productClassifyService.getOne(q -> q.eq(ProductClassify::getName, productInfoEhsdExcel.getProductClassifyName()));
            if (ObjectUtil.isEmpty(productClassify)) {
                throw new ServiceException("未知产品分类" + productInfoEhsdExcel.getProductClassifyName());
            }
            productInfo.setProductClassifyId(productClassify.getId());
            //单位名称转字典key
            if (ObjectUtil.isNotEmpty(productInfo.getUnit())) {
                String unit = unitMap.get(productInfo.getUnit());
                if (ObjectUtil.isEmpty(unit)) {
                    throw new ServiceException("未知单位" + productInfo.getUnit());
                }
                productInfo.setUnit(unit);
            }
            ProductInfoEhsdJson productInfoEhsdJson = BeanUtil.copyProperties(productInfoEhsdExcel, ProductInfoEhsdJson.class);
            productInfoEhsdJson.setType("1");//公司产品
            productInfoEhsdJson.setCustomerId("0");//客户id为0 公司产品
            //内外包装方式名称转字典key
            String innerPackMethod = productInfoEhsdJson.getInnerPackMethod();
            if (ObjectUtil.isNotEmpty(innerPackMethod)) {
                String[] split = innerPackMethod.split(",");
                for (int i = 0; i < split.length; i++) {
                    String key = innerPackMethodMap.get(split[i]);
                    if (ObjectUtil.isEmpty(key)) {
                        throw new ServiceException("未知内包装方式" + split[i]);
                    }
                    split[i] = key;
                }
                productInfoEhsdJson.setInnerPackMethod(String.join(",", split));
            }
            String outerPackMethod = productInfoEhsdJson.getOuterPackMethod();
            if (ObjectUtil.isNotEmpty(outerPackMethod)) {
                String[] split = outerPackMethod.split(",");
                for (int i = 0; i < split.length; i++) {
                    String key = outsidePackMethodMap.get(split[i]);
                    if (ObjectUtil.isEmpty(key)) {
                        throw new ServiceException("未知外包装方式" + split[i]);
                    }
                    split[i] = key;
                }
                productInfoEhsdJson.setOuterPackMethod(String.join(",", split));
            }
            productInfo.setEhsdJson(JSONObject.toJSONString(productInfoEhsdJson, JSONWriter.Feature.WriteLongAsString));
            productInfoList.add(productInfo);
        }
        saveBatch(productInfoList);
    }

    @DSTransactional
    @Override
    public void addByWdly(ProductInfoDto productInfoDto) {
        //处理维多利亚扩展
        String victoriatouristJson = productInfoDto.getVictoriatouristJson();
        if (ObjectUtil.isNotEmpty(victoriatouristJson)) {
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            json.put("deptId", SecurityUtils.getDeptId());
            productInfoDto.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }
        add(productInfoDto);
    }

    @DSTransactional
    @Override
    public void edit(ProductInfoDto productInfoDto) {
        // 禁止产品编号修改
        productInfoDto.setCode(null);
        //检查【产品名称】和【规格型号】不能同时重复，但可以单项重复。
        long nameAndSpecCount = this.count(q -> q
                .ne(ProductInfo::getId, productInfoDto.getId())
                .eq(ProductInfo::getName, productInfoDto.getName())
                .eq(ProductInfo::getSpec, productInfoDto.getSpec())
        );
        if (nameAndSpecCount != 0) {
            throw new ServiceException("同名称同规格的产品已存在");
        }
        // 排除不为空的自定义编码重复
        long count = this.count(q -> q
                .ne(ProductInfo::getId, productInfoDto.getId())
                .eq(ProductInfo::getCustomCode, productInfoDto.getCustomCode())
                .ne(ProductInfo::getCustomCode, ""));
        if (count != 0) {
            throw new ServiceException("产品自定义编码重复");
        }
        this.updateById(productInfoDto);
        ObsFileUtil.editFile(productInfoDto.getFileList(), productInfoDto.getId());
    }

    @DSTransactional
    @Override
    public void delete(Long id) {
        this.removeById(id);
        ObsFileUtil.removeFile(id);
    }

    /**
     * 根据产品IDS获取产品
     *
     * @param productIds
     * @return
     */
    @Override
    public List<ProductInfoVo> getListByProductIds(List<Long> productIds) {
        return baseMapper.getListByProductIds(productIds);
    }

    /**
     * 根据产品类型获取产品
     *
     * @param productType
     * @return
     */
    @Override
    public List<ProductInfoVo> getListByProductType(Integer productType, Integer definition, String productName, String productCode) {
        return baseMapper.getListByProductType(productType, definition, productName, productCode);
    }

    @Override
    public void excelImport(MultipartFile file) {
//        List<Object> read = ExcelUtil.read(file, Object.class);
    }

    @Override
    public void transfer(ProductInfoDto productInfoDto) {
        ProductInfo productInfo = getById(productInfoDto.getId());
        String victoriatouristJson = productInfo.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        json.put("deptId", productInfoDto.getDeptId());
        productInfo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        updateById(productInfo);
    }

    /**
     * 产品统计（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public Map<String, Object> productStatistics(ProductInfoDto productInfoDto) {
        if (ObjectUtil.isEmpty(productInfoDto) && ObjectUtil.isEmpty(productInfoDto.getBeginTime())
                && StringUtils.isNotEmpty(productInfoDto.getEndTime())) {
            throw new ServiceException("参数缺失：开始时间，结束时间不能为null");
        }
        //存放产品统计数据
        Map map = new HashMap();

        //存放产品类型数据
        List<Map<String, Object>> typeList = new ArrayList<>();
        QueryWrapper<ProductInfo> query = Wrappers.<ProductInfo>query();
        query.select("count(*) count,ifNull(type,999) type");
        query.groupBy("type");
        //查询每个类型的总计
        List<ProductInfo> productInfos = baseMapper.selectList(query);
        Map<String, List<ProductInfo>> productInfoTotalMap = productInfos.stream().collect(Collectors.groupingBy(ProductInfo::getType));
        query.ge("DATE_FORMAT(create_time,'%Y-%m-%d')", productInfoDto.getBeginTime());
        query.le("DATE_FORMAT(create_time,'%Y-%m-%d')", productInfoDto.getEndTime());
        //查询每个类型的新增数量
        List<ProductInfo> productInfoList = baseMapper.selectList(query);
        Map<String, List<ProductInfo>> productInfoTypeMap = productInfoList.stream().collect(Collectors.groupingBy(ProductInfo::getType));
        //计算新增总计
        Integer newTotal = productInfoList.stream().map(ProductInfo::getCount).reduce(Integer::sum).orElse(0);
        //总计
        Integer total = productInfos.stream().map(ProductInfo::getCount).reduce(Integer::sum).orElse(0);

        map.put("newTotal", newTotal);
        map.put("total", total);

        //获取产品类型的字典数据
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        List<DictTenantDataVo> dictTenantDataVoList = getDict("product_type");
        DynamicDataSourceContextHolder.poll();

        if (ObjectUtil.isEmpty(dictTenantDataVoList)) {
            return map;
        }

        for (DictTenantDataVo dictTenantDataVo : dictTenantDataVoList) {
            //存放每个类型的新增与总计
            Map<String, Object> map1 = new HashMap<>();
            //设置初使值
            map1.put("type", dictTenantDataVo.getDictKey());
            map1.put("typeNewTotal", 0);
            map1.put("typeTotal", 0);

            //赋值新增的款数
            List<ProductInfo> productInfoNewList = productInfoTypeMap.get(dictTenantDataVo.getDictKey());
            if (ObjectUtil.isNotEmpty(productInfoNewList)) {
                map1.put("typeNewTotal", productInfoNewList.get(0).getCount());
            }

            //赋值类型总计
            List<ProductInfo> productInfoTotalList = productInfoTotalMap.get(dictTenantDataVo.getDictKey());
            if (ObjectUtil.isNotEmpty(productInfoTotalList)) {
                map1.put("typeTotal", productInfoTotalList.get(0).getCount());
            }
            typeList.add(map1);
        }
        map.put("typeList", typeList);

        return map;
    }

    /**
     * 产品分布（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public List<Map<String, Object>> productDistribution(ProductInfoDto productInfoDto) {
        if (ObjectUtil.isEmpty(productInfoDto) && ObjectUtil.isEmpty(productInfoDto.getBeginTime())
                && StringUtils.isNotEmpty(productInfoDto.getEndTime())) {
            throw new ServiceException("参数缺失：开始时间，结束时间不能为null");
        }
        //存放产品分布列表
        List<Map<String, Object>> list = new ArrayList<>();

        QueryWrapper<ProductInfo> query = Wrappers.<ProductInfo>query();
        query.select("count(*) count,ifnull(type,999) type");
        query.groupBy("type");
        query.ge("DATE_FORMAT(create_time,'%Y-%m-%d')", productInfoDto.getBeginTime());
        query.le("DATE_FORMAT(create_time,'%Y-%m-%d')", productInfoDto.getEndTime());
        //查询每个类型的总计
        List<ProductInfo> productInfos = baseMapper.selectList(query);
        if (productInfos.size() == 0) {
            new ArrayList<>();
        }
        Map<String, List<ProductInfo>> productInfoMap = productInfos.stream().collect(Collectors.groupingBy(ProductInfo::getType));
        //获取产品类型的字典数据
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        List<DictTenantDataVo> dictTenantDataVoList = getDict("product_type");
        DynamicDataSourceContextHolder.poll();

        if (dictTenantDataVoList.size() == 0) {
            new ArrayList<>();
        }

        //赋值
        for (DictTenantDataVo dictTenantDataVo : dictTenantDataVoList) {
            Map<String, Object> map = new HashMap<>();
            //初始化
            map.put("type", dictTenantDataVo.getDictKey());
            map.put("name", dictTenantDataVo.getDictValue());
            map.put("count", 0);

            List<ProductInfo> productInfoList = productInfoMap.get(dictTenantDataVo.getDictKey());
            if (ObjectUtil.isNotEmpty(productInfoList)) {
                map.put("count", productInfoList.get(0).getCount());
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 产品类型排行（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public List<Map<String, Object>> productTypeRanking(ProductInfoSelectDto productInfoDto) {
        //存放产品类型排行数据
        List<Map<String, Object>> list = new ArrayList<>();

        QueryWrapper<Object> query = Wrappers.query();
        String beginTime = DateUtil.format(productInfoDto.getBeginTime(), "yyyy-MM-dd");
        String endTime = DateUtil.format(productInfoDto.getEndTime(), "yyyy-MM-dd");
        query.ge("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", beginTime);
        query.le("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", endTime);
        query.eq(ObjectUtil.isNotEmpty(productInfoDto.getCountryId()), "bc.buy_country_id", productInfoDto.getCountryId());
//        sort(query,productInfoDto);
        query.groupBy("pi.type");
        //查询产品类型排行数据
        List<ProductInfoVo> productInfoVos = baseMapper.productTypeRanking(query);
        if (productInfoVos.size() == 0) {
            return list;
        }
        Map<String, List<ProductInfoVo>> productInfoVoMap = productInfoVos.stream().collect(Collectors.groupingBy(ProductInfoVo::getType));
        //获取产品类型的字典数据
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        List<DictTenantDataVo> dictTenantDataVoList = getDict("product_type");
        DynamicDataSourceContextHolder.poll();

        //赋值
        for (DictTenantDataVo dictTenantDataVo : dictTenantDataVoList) {
            //初始化
            Map<String, Object> map = new HashMap<>();
            map.put("type", dictTenantDataVo.getDictKey());
            map.put("name", dictTenantDataVo.getDictValue());
            map.put("contractAmount", new BigDecimal(0));
            map.put("contractQuantity", new BigDecimal(0));
            map.put("purchaseAmount", new BigDecimal(0));
            map.put("purchaseQuantity", new BigDecimal(0));
            //赋值
            List<ProductInfoVo> productInfoVos1 = productInfoVoMap.get(dictTenantDataVo.getDictKey());
            if (ObjectUtil.isNotEmpty(productInfoVos1)) {
                map.put("contractAmount", productInfoVos1.get(0).getContractAmount());
                map.put("contractQuantity", productInfoVos1.get(0).getContractQuantity());
                map.put("purchaseAmount", productInfoVos1.get(0).getPurchaseAmount());
                map.put("purchaseQuantity", productInfoVos1.get(0).getPurchaseQuantity());
            }
            list.add(map);
        }
        if (ObjectUtil.isNotEmpty(list)) {
            //排序
            list = typeSort(list, productInfoDto);
        }
        return list;
    }

    /**
     * 产品分类排行（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public List<Map<String, Object>> productClassifyRanking(ProductInfoSelectDto productInfoDto) {
        //存放产品类型排行数据
        List<Map<String, Object>> list = new ArrayList<>();

        QueryWrapper<Object> query = Wrappers.query();
        String beginTime = DateUtil.format(productInfoDto.getBeginTime(), "yyyy-MM-dd");
        String endTime = DateUtil.format(productInfoDto.getEndTime(), "yyyy-MM-dd");
        query.ge("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", beginTime);
        query.le("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", endTime);
        query.eq(ObjectUtil.isNotEmpty(productInfoDto.getCountryId()), "bc.buy_country_id", productInfoDto.getCountryId());
        query.groupBy("pi.id");
        //查询产品类型排行数据
        List<ProductInfoVo> productInfoVos = baseMapper.productTypeRanking(query);
        if (productInfoVos.size() == 0) {
            return list;
        }

        //获取所有产品分类
        List<ProductClassify> productClassifyList = productClassifyService.list();
        //获取顶级分类
        List<ProductClassify> topProductClassifyList = productClassifyList.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());

        //赋值
        for (ProductClassify productClassify : topProductClassifyList) {
            //初始化
            Map<String, Object> map = new HashMap<>();
            map.put("name", productClassify.getName());
            map.put("contractAmount", new BigDecimal(0));
            map.put("contractQuantity", new BigDecimal(0));
            map.put("purchaseAmount", new BigDecimal(0));
            map.put("purchaseQuantity", new BigDecimal(0));
            //赋值
            List<ProductInfoVo> productInfoVos1 = productInfoVos.stream().filter(item ->
                    item.getProductClassifyId().equals(productClassify.getId())
                            || (ObjectUtil.isEmpty(item.getParentIdSet()) ? "0" : item.getParentIdSet()).contains(productClassify.getId().toString())
            ).collect(Collectors.toList());
            if (ObjectUtil.isNotEmpty(productInfoVos1)) {
                map.put("contractAmount", productInfoVos1.get(0).getContractAmount());
                map.put("contractQuantity", productInfoVos1.get(0).getContractQuantity());
                map.put("purchaseAmount", productInfoVos1.get(0).getPurchaseAmount());
                map.put("purchaseQuantity", productInfoVos1.get(0).getPurchaseQuantity());
            }
            list.add(map);
        }
        if (ObjectUtil.isNotEmpty(list)) {
            //排序
            list = typeSort(list, productInfoDto);
        }
        return list;
    }


    /**
     * 产品排行（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public Page<ProductInfoVo> productRanking(ProductInfoSelectDto productInfoDto) {
        QueryWrapper<Object> query = Wrappers.query();
        String beginTime = DateUtil.format(productInfoDto.getBeginTime(), "yyyy-MM-dd");
        String endTime = DateUtil.format(productInfoDto.getEndTime(), "yyyy-MM-dd");
        query.ge("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", beginTime);
        query.le("DATE_FORMAT(pc.create_time,'%Y-%m-%d')", endTime);
        query.eq(ObjectUtil.isNotEmpty(productInfoDto.getCountryId()), "bc.buy_country_id", productInfoDto.getCountryId());
        sort(query, productInfoDto);
        query.groupBy("pi.name");
        Page<ProductInfoVo> productInfoVos = baseMapper.productRanking(productInfoDto.getPage(), query);
        return productInfoVos;
    }

    /**
     * 产品统计
     *
     * @return
     */
    @Override
    public Map<String, Object> statisticsProduct() {
        return baseMapper.statisticsProduct();
    }

    /**
     * 产品库统计(根据产品库类型进行分类统计)
     */
    @Override
    public Map<String, Object> productInfoStatistics(ProductInfoSelectDto dto) {
        //存放产品库统计数据
        Map<String, Object> map = new HashMap<>();

        //存放产品分类统计数据
        List<Map<String, Object>> list = new ArrayList<>();
        QueryWrapper<ProductInfo> wrapper = Wrappers.query();
        wrapper.groupBy("type");
        wrapper.select("count(*) count, ifNull(type,-1) type");
        List<ProductInfo> productInfos = baseMapper.selectList(wrapper);
        Map<String, List<ProductInfo>> productInfoMap = productInfos.stream().collect(Collectors.groupingBy(ProductInfo::getType));

        //计算统计合计
        Integer amount = productInfos.stream().map(productInfo -> productInfo.getCount()).reduce(Integer::sum).orElse(0);

        map.put("amount", amount);
        //获取产品类型统计数据
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        List<DictTenantDataVo> dictTenantDataVoList = getDict("product_type");
        DynamicDataSourceContextHolder.poll();
        if (dictTenantDataVoList.size() == 0) {
            throw new ServiceException("数据异常：产品没有设置产品类型字典，请先添加");
        }

        for (DictTenantDataVo dictTenantDataVo : dictTenantDataVoList) {
            Map typeMap = new HashMap();
            //设置初始值
            typeMap.put("type", dictTenantDataVo.getDictValue());
            typeMap.put("count", 0);

            //赋值
            List<ProductInfo> productInfoList = productInfoMap.get(dictTenantDataVo.getDictKey());
            if (CollectionUtils.isNotEmpty(productInfoList)) {
                typeMap.put("count", productInfoList.get(0).getCount());
            }
            list.add(typeMap);

        }
        map.put("typeList", list);
        return map;
    }


    //根据字典编码获取字典的数据
    private List<DictTenantDataVo> getDict(String code) {
        DictTenantDataSelectDto dto = new DictTenantDataSelectDto();
        dto.setDictCode(code);
        List<DictTenantDataVo> dictTenantDataServiceList = dictTenantDataService.getList(dto);
        return dictTenantDataServiceList;
    }

    //排序(添加排序条件)
    private void sort(QueryWrapper<Object> query, ProductInfoSelectDto productInfoDto) {
        if (productInfoDto.getOrderBy() == 10) {//正序
            query.orderByAsc(productInfoDto.getSort() == 10, "contractQuantity");
            query.orderByAsc(productInfoDto.getSort() == 20, "contractAmount");
            query.orderByAsc(productInfoDto.getSort() == 30, "purchaseQuantity");
            query.orderByAsc(productInfoDto.getSort() == 40, "purchaseAmount");
        } else if (productInfoDto.getOrderBy() == 20) {//倒序
            query.orderByDesc(productInfoDto.getSort() == 10, "contractQuantity");
            query.orderByDesc(productInfoDto.getSort() == 20, "contractAmount");
            query.orderByDesc(productInfoDto.getSort() == 30, "purchaseQuantity");
            query.orderByDesc(productInfoDto.getSort() == 40, "purchaseAmount");
        }
    }

    //产品类型排序
    private List<Map<String, Object>> typeSort(List<Map<String, Object>> list, ProductInfoSelectDto productInfoSelectDto) {
        if (productInfoSelectDto.getOrderBy() == 10) {
            if (productInfoSelectDto.getSort() == 10) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("contractQuantity").toString())))
                        .collect(Collectors.toList());
                return list;
            } else if (productInfoSelectDto.getSort() == 20) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("contractAmount").toString())))
                        .collect(Collectors.toList());
                return list;
            } else if (productInfoSelectDto.getSort() == 30) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("purchaseQuantity").toString())))
                        .collect(Collectors.toList());
                return list;
            } else if (productInfoSelectDto.getSort() == 40) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("purchaseAmount").toString())))
                        .collect(Collectors.toList());
                return list;
            }
        } else {
            if (productInfoSelectDto.getSort() == 10) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("contractQuantity").toString())))
                        .collect(Collectors.toList());
                Collections.reverse(list);
                return list;
            } else if (productInfoSelectDto.getSort() == 20) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("contractAmount").toString())))
                        .collect(Collectors.toList());
                Collections.reverse(list);
                return list;
            } else if (productInfoSelectDto.getSort() == 30) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("purchaseQuantity").toString())))
                        .collect(Collectors.toList());
                Collections.reverse(list);
                return list;
            } else if (productInfoSelectDto.getSort() == 40) {
                list = list.stream()
                        .sorted(Comparator.comparing(m -> new BigDecimal(m.get("purchaseAmount").toString())))
                        .collect(Collectors.toList());
                Collections.reverse(list);
                return list;
            }
        }
        return list;
    }

}
