package com.fjhx.sale.flow;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fjhx.common.entity.AvailableStockBo;
import com.fjhx.common.enums.FlowStatusEnum1;
import com.fjhx.common.utils.Assert;
import com.fjhx.common.utils.Utils;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.flow.core.FlowDelegate;
import com.fjhx.flow.enums.FlowStatusEnum;
import com.fjhx.item.enums.ProductAvailableRecordType;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.purchase.entity.purchase.enums.PurchaseStatusEnum;
import com.fjhx.purchase.entity.subscribe.po.SubscribeDetail;
import com.fjhx.purchase.service.subscribe.SubscribeDetailService;
import com.fjhx.sale.entity.contract.dto.ContractDto;
import com.fjhx.sale.entity.contract.dto.ContractProductDto;
import com.fjhx.sale.entity.contract.po.Contract;
import com.fjhx.sale.entity.contract.po.ContractProduct;
import com.fjhx.sale.entity.contract.po.ContractProductBom;
import com.fjhx.sale.entity.contract.po.ContractProject;
import com.fjhx.sale.entity.contract.vo.ContractProductBomVo;
import com.fjhx.sale.entity.purchase.po.EhsdPurchaseProduct;
import com.fjhx.sale.entity.purchase.vo.EhsdPurchaseProductVo;
import com.fjhx.sale.mapper.purchase.EhsdPurchaseProductMapper;
import com.fjhx.sale.service.contract.ContractProductBomService;
import com.fjhx.sale.service.contract.ContractProductService;
import com.fjhx.sale.service.contract.ContractProjectService;
import com.fjhx.sale.service.contract.ContractService;
import com.fjhx.sale.service.purchase.EhsdPurchaseProductService;
import com.ruoyi.common.core.domain.BasePo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 合同变更流程
 */
@Component
public class ContractUpdateFlow extends FlowDelegate {

    @Autowired
    private ContractFlow contractFlow;

    @Autowired
    private ContractService contractService;

    @Autowired
    private ContractProductService contractProductService;
    @Autowired
    private ContractProductBomService contractProductBomService;
    @Autowired
    private ContractProjectService contractProjectService;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private EhsdPurchaseProductService ehsdPurchaseProductService;
    @Autowired
    private EhsdPurchaseProductMapper ehsdPurchaseProductMapper;
    @Autowired
    private SubscribeDetailService subscribeDetailService;

    @Override
    public String getFlowKey() {
        return "contract_update_flow";
    }

    /**
     * 发起流程
     */
    @Override
    public Long start(Long flowId, JSONObject submitData) {
        ContractDto contract = submitData.toJavaObject(ContractDto.class);
        Assert.notEmpty(contract.getId(), "原销售订单id不能为空");
        //赋值原采购id 并 清空id
        contract.setOldContractId(contract.getId());
        contract.setId(null);

        //赋值流程id
        contract.setFlowId(flowId);

        //原合同id不能为空
        Long oldContractId = contract.getOldContractId();
        Assert.notEmpty(oldContractId, "原合同id不能为空");
        //查询原合同
        Contract oldContract = contractService.getById(contract.getOldContractId());
        Assert.notEmpty(oldContract, "查询不到原合同信息");
        //判断合同是否在变更中，防止用户缓存导致重复变更
        if (oldContract.getStatus().equals(FlowStatusEnum1.UPDATE_LOADING.getKey())) {
            throw new ServiceException("原合同正在变更中，禁止重复变更！");
        }

        //将原合同改为变更中
        contractService.update(q -> q.eq(Contract::getId, oldContractId).set(Contract::getStatus, FlowStatusEnum1.UPDATE_LOADING.getKey()));

        //赋值变更后的单号新单号
        contract.setCode(Utils.getNewCode(oldContract.getCode()));
        contract.setIsShow(1);//隐藏当前数据

        //清理明细id
        List<ContractProductDto> contractProductList = contract.getContractProductList();
        List<ContractProject> contractProjectList = contract.getContractProjectList();

        //防止空指针
        contractProductList = ObjectUtils.isEmpty(contractProductList) ? new ArrayList<>() : contractProductList;
        contractProjectList = ObjectUtils.isEmpty(contractProjectList) ? new ArrayList<>() : contractProjectList;

        //清空bomId
        for (ContractProductDto contractProductDto : contractProductList) {
            contractProductDto.setId(null);

            List<ContractProductBom> contractProductBomList = contractProductDto.getContractProductBomList();
            contractProductBomList = ObjectUtils.isEmpty(contractProductBomList) ? new ArrayList<>() : contractProductBomList;
            contractProductBomList.forEach(item -> item.setId(null));
        }

        //清空id
        contractProjectList.forEach(item -> item.setId(null));


        //调用合同发起通用代码
        Long start = contractFlow.start(contract);

        //将code赋值给流程引擎
        submitData.put("code", contract.getCode());

        return start;
    }

    /**
     * 结束流程
     */
    @Override
    public void end(Long flowId, Long businessId, JSONObject submitData) {

        // 通过业务ID查询合同数据
        Contract newContract = contractService.getById(businessId);
        Long oldContractId = newContract.getOldContractId();


        Contract oldContract = contractService.getById(oldContractId);

        //修改采购状态为审批通过
        newContract.setStatus(PurchaseStatusEnum.PASS.getKey());
        newContract.setApprovedDate(new Date());
        contractService.updateById(newContract);

        //原合同改为 已变更
        oldContract.setStatus(FlowStatusEnum1.UPDATE.getKey());
        contractService.updateById(oldContract);


        //----------修改可用库存---------
        if (Objects.equals(1, oldContract.getOrderDistributeStatus())) {

            editAvailableStock(oldContract, oldContractId, businessId);
        }
        //-----------------
        //交换合同产品BOM中的合同id
        List<ContractProductBom> oldCpbList = contractProductBomService.list(q -> q.eq(ContractProductBom::getContractId, oldContractId));
        List<ContractProductBom> newCpbList = contractProductBomService.list(q -> q.eq(ContractProductBom::getContractId, businessId));
        oldCpbList.forEach(item -> item.setContractId(businessId));
        newCpbList.forEach(item -> item.setContractId(oldContractId));
        contractProductBomService.updateBatchById(oldCpbList);
        contractProductBomService.updateBatchById(newCpbList);
        //-----------------

        //替换新数据ID为临时ID
        long temNewId = IdWorker.getId();
        Contract temNewUpContract = new Contract();
        temNewUpContract.setId(temNewId);
        temNewUpContract.setUpId(businessId);
        contractService.updateContract(temNewUpContract);

        long temOldId = IdWorker.getId();
        Contract temOldUpContract = new Contract();
        temOldUpContract.setId(temOldId);
        temOldUpContract.setUpId(oldContractId);
        contractService.updateContract(temOldUpContract);


        //查询新数据产品、收费
        List<Long> newContractProductIds = contractProductService.list(Wrappers.<ContractProduct>query().lambda().select(ContractProduct::getId).eq(ContractProduct::getContractId, businessId)).stream().map(ContractProduct::getId).collect(Collectors.toList());
        List<Long> newContractProjectIds = contractProjectService.list(Wrappers.<ContractProject>query().lambda().select(ContractProject::getId).eq(ContractProject::getContractId, businessId)).stream().map(ContractProject::getId).collect(Collectors.toList());


        //查询旧数据产品、收费
        List<Long> oldContractProductIds = contractProductService.list(Wrappers.<ContractProduct>query().lambda().select(ContractProduct::getId).eq(ContractProduct::getContractId, oldContractId)).stream().map(ContractProduct::getId).collect(Collectors.toList());
        List<Long> oldContractProjectIds = contractProjectService.list(Wrappers.<ContractProject>query().lambda().select(ContractProject::getId).eq(ContractProject::getContractId, oldContractId)).stream().map(ContractProject::getId).collect(Collectors.toList());


        /**
         * 处理新合同---
         */
        newContract.setId(oldContractId);//id赋值为旧合同的id
        newContract.setStatus(FlowStatusEnum1.PASS.getKey());
        newContract.setApprovedDate(new Date());
        newContract.setUpId(temNewId);
        newContract.setOldContractId(businessId);
        newContract.setIsShow(0);//显示新合同
        contractService.updateContract(newContract);
        //修改合同产品相关数据
        if (CollectionUtils.isNotEmpty(newContractProductIds)) {
            contractProductService.update(Wrappers.<ContractProduct>update().lambda().set(ContractProduct::getContractId, oldContractId).in(ContractProduct::getId, newContractProductIds));
        }
        //修改合同收费相关数据
        if (CollectionUtils.isNotEmpty(newContractProjectIds)) {
            contractProjectService.update(Wrappers.<ContractProject>update().lambda().set(ContractProject::getContractId, oldContractId).in(ContractProject::getId, newContractProjectIds));
        }

        /**
         * 处理旧的合同---
         */
        oldContract.setId(businessId);
        oldContract.setStatus(FlowStatusEnum1.UPDATE.getKey());
        oldContract.setIsChange("1");
        oldContract.setUpId(temOldId);
        oldContract.setIsShow(1);//隐藏旧合同
        contractService.updateContract(oldContract);
        //修改合同产品相关数据
        if (CollectionUtils.isNotEmpty(oldContractProductIds)) {
            contractProductService.update(Wrappers.<ContractProduct>update().lambda().set(ContractProduct::getContractId, businessId).in(ContractProduct::getId, oldContractProductIds));
        }
        //修改合同出货相关数据
        if (CollectionUtils.isNotEmpty(oldContractProjectIds)) {
            //修改合同收费相关数据
            contractProjectService.update(Wrappers.<ContractProject>update().lambda().set(ContractProject::getContractId, businessId).in(ContractProject::getId, oldContractProjectIds));
        }
        ObsFileUtil.exchangeBusinessId(oldContractId, businessId);

//        throw new ServiceException("1111111111111111111111111");

    }

    void editAvailableStock(Contract oldContract, Long oldContractId, Long businessId) {
        //---------------------------------------------------------------
        List<ContractProductBomVo> oldProductBomListSum = contractProductBomService.getContractProductBomQuantitySum(oldContractId);

        //获取新合同物料数量Map
        List<ContractProductBomVo> contractProductBomQuantitySum = contractProductBomService.getContractProductBomQuantitySum(businessId);
        Map<Long, BigDecimal> newQuantityMap = contractProductBomQuantitySum.stream().collect(Collectors.toMap(ContractProductBom::getMaterialId, ContractProductBom::getQuantity));


        List<AvailableStockBo> availableStockBoList = new ArrayList<>();

        //获取原合同已采购数量
        List<EhsdPurchaseProductVo> purchaseQuantitySumByContractId = ehsdPurchaseProductMapper.getPurchaseQuantitySumByContractId(oldContractId);
        Map<Long, BigDecimal> collect = purchaseQuantitySumByContractId.stream().collect(Collectors.toMap(EhsdPurchaseProduct::getProductId, EhsdPurchaseProduct::getQuantity));

        //旧数据处理
        for (ContractProductBomVo oldContractProductBom : oldProductBomListSum) {
            Long materialId = oldContractProductBom.getMaterialId();

            //新数量
            BigDecimal newQuantity = newQuantityMap.get(materialId);
            //已采购数量
            BigDecimal purchaseQuantity = collect.getOrDefault(materialId, BigDecimal.ZERO);

            //获取原需采购量
            SubscribeDetail subscribeDetail = subscribeDetailService.getOne(q -> q.eq(SubscribeDetail::getContractId, oldContractId)
                    .eq(SubscribeDetail::getProductId, materialId)
            );
            BigDecimal demandPurchaseCount = BigDecimal.ZERO;
            if (ObjectUtils.isNotEmpty(subscribeDetail)) {
                demandPurchaseCount = subscribeDetail.getCount();
            }


            //生成操作可用库存的实体
            AvailableStockBo availableStockBo = new AvailableStockBo();
            availableStockBo.setProductId(materialId);
            availableStockBo.setQuantity(oldContractProductBom.getQuantity());
            availableStockBo.setNewQuantity(newQuantity);
            availableStockBo.setInStockQuantity(purchaseQuantity);
            availableStockBo.setDemandPurchaseCount(demandPurchaseCount);

            availableStockBoList.add(availableStockBo);

        }

        //新添加的数据处理
        Map<Long, BigDecimal> oldQuantityMap = oldProductBomListSum.stream().collect(Collectors.toMap(ContractProductBom::getMaterialId, ContractProductBom::getQuantity));
        for (ContractProductBomVo newPurchaseProduct : contractProductBomQuantitySum) {
            Long materialId = newPurchaseProduct.getMaterialId();

            BigDecimal bigDecimal = oldQuantityMap.get(materialId);
            //忽略掉变更前有的物料
            if (ObjectUtils.isNotEmpty(bigDecimal)) {
                continue;
            }

            //生成操作可用库存的实体
            AvailableStockBo availableStockBo = new AvailableStockBo();
            availableStockBo.setProductId(materialId);
            availableStockBo.setQuantity(BigDecimal.ZERO);
            availableStockBo.setNewQuantity(newPurchaseProduct.getQuantity());
            availableStockBo.setInStockQuantity(BigDecimal.ZERO);
            availableStockBo.setDemandPurchaseCount(BigDecimal.ZERO);

            availableStockBoList.add(availableStockBo);
        }


        //修改可用库存
        productInfoService.editAvailableQuantity(availableStockBoList, businessId, ProductAvailableRecordType.SALE_UPDATE, oldContract.getCompanyId());


        //修该待采购量为需采购量
        for (AvailableStockBo availableStockBo : availableStockBoList) {

            Long materialId = availableStockBo.getProductId();
            SubscribeDetail subscribeDetail = subscribeDetailService.getOne(q -> q.eq(SubscribeDetail::getContractId, oldContractId)
                    .eq(SubscribeDetail::getProductId, materialId)
            );

            BigDecimal requiredQuantity = availableStockBo.getNewQuantity();


            //需采购量>0
            if (requiredQuantity.compareTo(BigDecimal.ZERO) > 0) {
                if (ObjectUtils.isEmpty(subscribeDetail)) {
                    //生成待采购
                    subscribeDetail = new SubscribeDetail();
                    subscribeDetail.setProductId(materialId);
                    subscribeDetail.setCount(BigDecimal.ZERO);
                    subscribeDetail.setStatus(15);//待采购
                    subscribeDetail.setContractId(oldContractId);
                    subscribeDetail.setDataType(1);
                    subscribeDetail.setCompanyId(oldContract.getCompanyId());
                }

                //修改待采购量
                subscribeDetail.setCount(requiredQuantity);

                //计算状态
                BigDecimal purchaseQuantity = availableStockBo.getInStockQuantity();
                int status = purchaseQuantity.compareTo(requiredQuantity) >= 0 ? 20 : 30;
                if (purchaseQuantity.compareTo(BigDecimal.ZERO) == 0) {
                    status = 15;
                }
                subscribeDetail.setStatus(status);

                subscribeDetailService.saveOrUpdate(subscribeDetail);
            } else {
                //需采购==0不显示或删除,<不存在
                if (ObjectUtils.isNotEmpty(subscribeDetail)) {
                    subscribeDetailService.removeById(subscribeDetail);
                }
            }


        }

        //---------------------------------------------------------------
    }


    /**
     * 重新发起
     */
    @Override
    public void relaunch(Long flowId, Long businessId, FlowStatusEnum flowStatus, JSONObject submitData) {
        contractFlow.relaunch(flowId, businessId, flowStatus, submitData);
    }

    /**
     * 驳回
     */
    @Override
    public void reject(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
        contractFlow.reject(flowId, businessId, flowStatus);
        //恢复原合同
        Contract contract = contractService.getById(businessId);
        contractService.update(q -> q
                .eq(Contract::getId, contract.getOldContractId())
                .set(Contract::getStatus, FlowStatusEnum1.PASS.getKey())
                .set(Contract::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

    @Override
    public void cancellation(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
        contractFlow.cancellation(flowId, businessId, flowStatus);
        //恢复原合同
        Contract contract = contractService.getById(businessId);
        contractService.update(q -> q
                .eq(Contract::getId, contract.getOldContractId())
                .set(Contract::getStatus, FlowStatusEnum1.PASS.getKey())
                .set(Contract::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }
}
