package com.fjhx.sale.flow;

import cn.hutool.core.util.ObjectUtil;
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.account.entity.account.po.AccountRunningWater;
import com.fjhx.account.service.account.AccountRunningWaterService;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.enums.FlowStatusEnum1;
import com.fjhx.common.utils.Assert;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.flow.core.FlowDelegate;
import com.fjhx.flow.enums.FlowStatusEnum;
import com.fjhx.sale.entity.claim.po.Claim;
import com.fjhx.sale.entity.claim.po.ClaimContract;
import com.fjhx.sale.entity.contract.dto.ContractDto;
import com.fjhx.sale.entity.contract.po.Contract;
import com.fjhx.sale.entity.contract.po.ContractProduct;
import com.fjhx.sale.entity.contract.po.ContractProject;
import com.fjhx.sale.entity.contract.po.ContractShipment;
import com.fjhx.sale.service.claim.ClaimContractService;
import com.fjhx.sale.service.claim.ClaimService;
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.contract.ContractShipmentService;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.core.domain.BasePo;
import com.ruoyi.common.core.domain.entity.SysUser;
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.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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 ClaimContractService claimContractService;

    @Autowired
    private AccountRunningWaterService accountRunningWaterService;

    @Autowired
    private ClaimService claimService;

    @Autowired
    private ContractProjectService contractProjectService;

    @Autowired
    private ContractShipmentService contractShipmentService;

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

    /**
     * 发起流程
     *
     * @param flowId     流程ID
     * @param submitData 采购付款数据
     * @return
     */
    @Override
    public Long start(Long flowId, JSONObject submitData) {
        ContractDto contract = submitData.toJavaObject(ContractDto.class);

        contract.setIssue("1");//默认直接下发到交接单

        contract.setFlowId(flowId);

        // 原合同id不能为空
        Long oldContractId = contract.getOldContractId();
        if (oldContractId == null) {
            throw new ServiceException("原合同id不能为空");
        }
        //查询原合同
        Contract oldContract = contractService.getById(contract.getOldContractId());
        if (ObjectUtil.isEmpty(oldContract)) {
            throw new ServiceException("查询不到原合同信息");
        }
        //更新原样品单状态为变更中
        oldContract.setStatus(FlowStatusEnum1.UPDATE_LOADING.getKey());
        contractService.updateById(oldContract);
        //查询旧合同的订单产品
        List<ContractProduct> oldContractProductList = contractProductService.list(q -> q.eq(ContractProduct::getContractId, oldContractId));
        if (CollectionUtils.isEmpty(oldContractProductList)) {
            throw new ServiceException("原合同没有产品");
        }
        Map<Long, List<ContractProduct>> oldContractProductMap = oldContractProductList.stream().collect(Collectors.groupingBy(ContractProduct::getId));
        List<ContractProduct> newContractProductList = contract.getContractProductList();
        if (CollectionUtils.isEmpty(newContractProductList)) {
            throw new ServiceException("变更合同产品不能为空");
        }
        /**
         * 赋值新的变更合同号
         */
        String code = oldContract.getCode();
        Matcher matcher = Pattern.compile(".*\\((.*?)\\)$").matcher(code);
        int index = 2;
        if (matcher.find()) {
            index = (Integer.parseInt(matcher.group(1)) + 1);
            code = code.substring(0, code.lastIndexOf("("));
        }
        contract.setCode(code + "(" + index + ")");
        contract.setIsShow(1);//隐藏当前数据
        /**
         * 计算新合同的剩余数量
         */
        for (ContractProduct newCp : newContractProductList) {
            newCp.setExpendQuantity(newCp.getQuantity());
            if (ObjectUtil.isNotEmpty(newCp.getId())) {//如果新合同产品ID不为空
                //取出旧合同
                ContractProduct oldContractProduct = oldContractProductMap.getOrDefault(newCp.getId(), null).get(0);
//                //取出旧合同包装方式
//                JSONObject oldJson = JSONObject.parseObject(oldContractProduct.getEhsdJson());
//                String oldPackMethod = oldJson.getOrDefault("packMethod",null)==null?null:oldJson.getOrDefault("packMethod",null).toString();
//                //取出新合同包装方式
//                JSONObject newJson = JSONObject.parseObject(newCp.getEhsdJson());
//                String newPackMethod = newJson.getOrDefault("packMethod",null)==null?null:oldJson.getOrDefault("packMethod",null).toString();
                /**
                 * 商品英文名、尺寸、包装方式、数量 没有变更---取原本的剩余数量
                 */
                if (oldContractProduct.getQuantity().compareTo(newCp.getQuantity()) == 0) {//如果数量没有变动
                    //取出旧的剩余数量
                    newCp.setExpendQuantity(oldContractProduct.getExpendQuantity());
                } else {//变动了
                    BigDecimal quantity = newCp.getQuantity().subtract(oldContractProduct.getQuantity()).subtract(oldContractProduct.getExpendQuantity());//剩余数量
                    newCp.setExpendQuantity(quantity);
                }
            }
        }
        return update(contract);
    }

    /**
     * 变更
     *
     * @param contract
     * @return
     */
    public Long update(ContractDto contract) {
        // 赋值城市省份信息
        CustomizeAreaUtil.setAreaId(contract);
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        contract.setUserName(loginUser.getNickName());
        contract.setBuyCityId(contract.getCityId());
        contract.setBuyCountryId(contract.getCountryId());
        contract.setBuyProvinceId(contract.getProvinceId());
        contract.setStatus(FlowStatusEnum1.UNDER_REVIEW.getKey());
//        contract.setRate(ExchangeRateUtil.getCnyToCodeRate(contract.getCurrency()));
        contractService.save(contract);

        // 保存合同产品
        List<ContractProduct> contractProductList = contract.getContractProductList();
        if (CollectionUtils.isNotEmpty(contractProductList)) {
            for (ContractProduct c : contractProductList) {
                c.setId(IdWorker.getId());
                c.setContractId(contract.getId());
//                ObsFileUtil.saveFile(c.getFileList(), c.getId());
            }
            contractProductService.saveBatch(contractProductList);
        }

        // 保存收费项目
        List<ContractProject> contractProjectList = contract.getContractProjectList();
        if (CollectionUtils.isNotEmpty(contractProjectList)) {
            for (ContractProject c : contractProjectList) {
                c.setId(IdWorker.getId());
                c.setContractId(contract.getId());
            }
            contractProjectService.saveBatch(contractProjectList);
        }

        // 保存自定义出货
        List<ContractShipment> contractShipmentList = contract.getContractShipmentList();
        if (CollectionUtils.isNotEmpty(contractShipmentList)) {
            for (ContractShipment c : contractShipmentList) {
                c.setId(IdWorker.getId());
                c.setContractId(contract.getId());
            }
            contractShipmentService.saveBatch(contractShipmentList);
        }

        // 交接单附件列表
        ObsFileUtil.copyFileAndSave(contract.getFileList(), contract.getId(), 1);

        // 包装指示附件列表
        ObsFileUtil.copyFileAndSave(contract.getPackageFileList(), contract.getId(), 2);

        return contract.getId();
    }

    /**
     * 结束流程
     *
     * @param flowId     流程ID
     * @param businessId 业务ID
     * @param submitData 数据
     */
    @Override
    public void end(Long flowId, Long businessId, JSONObject submitData) {
        // 通过业务ID查询合同数据
        Contract newContract = contractService.getById(businessId);
        if (ObjectUtils.isEmpty(newContract)) {
            throw new ServiceException("合同不存在");
        }
        long oldContractId = newContract.getOldContractId();//取出旧的合同ID
        Contract oldContract = contractService.getById(oldContractId);
        if (oldContract == null) {
            throw new ServiceException("原合同不存在");
        }
        //替换新数据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> newContractShipmentIds = contractShipmentService.list(Wrappers.<ContractShipment>query().lambda().select(ContractShipment::getId).eq(ContractShipment::getContractId, businessId)).stream().map(ContractShipment::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());
        List<Long> oldContractShipmentIds = contractShipmentService.list(Wrappers.<ContractShipment>query().lambda().select(ContractShipment::getId).eq(ContractShipment::getContractId, oldContractId)).stream().map(ContractShipment::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));
        }
        //修改合同出货相关数据
        if (CollectionUtils.isNotEmpty(newContractShipmentIds)) {
            contractShipmentService.update(Wrappers.<ContractShipment>update().lambda().set(ContractShipment::getContractId, oldContractId).in(ContractShipment::getId, newContractShipmentIds));
        }

        /**
         * 处理旧的合同---
         */
        oldContract.setId(businessId);
        oldContract.setStatus(FlowStatusEnum1.UPDATE.getKey());
        oldContract.setIsChange("1");
        contractService.updateById(oldContract);


        List<ClaimContract> claimContractList = claimContractService.list(Wrappers.<ClaimContract>query().lambda().eq(ClaimContract::getContractId, oldContractId));
        if (ObjectUtil.isNotEmpty(claimContractList)) {
            List<Long> claimIds = claimContractList.stream().map(ClaimContract::getClaimId).collect(Collectors.toList());
            List<Long> claimContractIds = claimContractList.stream().map(ClaimContract::getId).collect(Collectors.toList());
            //取出到账认领数据
            List<Claim> claims = claimService.list(q -> q.in(Claim::getId, CollectionUtils.isEmpty(claimIds) ? Arrays.asList("0000") : claimIds));
            for (Claim c : claims) {
                //查询流水数据
                AccountRunningWater accountRunningWater = accountRunningWaterService.getById(c.getBusinessId());
                BigDecimal sumClaimMoney = accountRunningWater.getClaimAmount().subtract(c.getAmount());
                //更新流水数据为认领状态---已认领金额还原
                AccountRunningWater water = new AccountRunningWater();
                if (sumClaimMoney.compareTo(BigDecimal.ZERO) > 0) {
                    water.setIsClaim(2);//部分认领
                } else {
                    water.setIsClaim(0);//未认领
                }
                water.setId(c.getBusinessId());
                water.setClaimAmount(sumClaimMoney);
                accountRunningWaterService.updateById(water);
            }
            //删除到账认领数据
            claimContractService.remove(q -> q.in(ClaimContract::getId, claimContractIds));
            //删除到账认领数据
            claimService.remove(q -> q.in(Claim::getId, claimIds));
        }

        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));
        }
        //修改合同出货相关数据
        if (CollectionUtils.isNotEmpty(oldContractShipmentIds)) {
            //修改合同出货相关数据
            contractShipmentService.update(Wrappers.<ContractShipment>update().lambda().set(ContractShipment::getContractId, businessId).in(ContractShipment::getId, oldContractShipmentIds));
        }
        ObsFileUtil.exchangeBusinessId(oldContractId, businessId);
    }

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


    /**
     * 驳回
     *
     * @param flowId
     * @param businessId
     * @param flowStatus
     */
    @Override
    public void reject(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
        super.reject(flowId, businessId, flowStatus);
        reject(businessId);
    }

    /**
     * 作废
     *
     * @param flowId     流程id
     * @param businessId 业务id
     * @param flowStatus 流程状态枚举
     */
    @Override
    public void cancellation(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
        super.cancellation(flowId, businessId, flowStatus);
        contractService.update(q -> q
                .eq(Contract::getId, businessId)
                .set(Contract::getStatus, FlowStatusEnum1.CANCELLATION.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
        //合同变更作废需要还原旧合同状态 为审批通过
        Contract contract = contractService.getById(businessId);
        contractService.update(q -> q
                .eq(Contract::getId, contract.getOldContractId())
                .set(Contract::getStatus, FlowStatusEnum1.PASS.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

    /**
     * 变更合同时执行的数据操作公共代码
     */
    private ContractDto opDate(ContractDto contract) {
        // 原合同id不能为空
        Long oldContractId = contract.getOldContractId();
        if (oldContractId == null) {
            throw new ServiceException("原合同id不能为空");
        }

        List<ContractProduct> list = contractProductService.list(q -> q.eq(ContractProduct::getContractId, oldContractId));

        // 赋值待处理数量
        if (CollectionUtils.isNotEmpty(list)) {

            List<ContractProduct> contractProductList = contract.getContractProductList();

            if (ObjectUtil.isEmpty(contractProductList)) {
                throw new ServiceException("没有合同产品");
            }

            Map<Long, ContractProduct> contractProductMap = contractProductList
                    .stream()
                    .filter(item -> ObjectUtil.isNotEmpty(item.getId()))
                    .collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));


            for (ContractProduct item : list) {
                ContractProduct contractProduct = contractProductMap.get(item.getId());
                if (ObjectUtil.isNotEmpty(contractProduct)) {
                    BigDecimal expendQuantity = item.getExpendQuantity().subtract(item.getQuantity().subtract(contractProduct.getQuantity()));
                    contractProduct.setExpendQuantity(expendQuantity);
                }
            }

        }
        return contract;
    }

    /**
     * 重新发起
     */
    private void reStart(JSONObject submitData) {
        ContractDto contract = submitData.toJavaObject(ContractDto.class);

        Assert.notEmpty(contract.getOldContractId(), "合同id不能为空");

        //变更合同需要提前操作数据
        contract = opDate(contract);

        contractFlow.reStartUpdate(contract);
    }

    /**
     * 驳回
     */
    private void reject(Long businessId) {
        contractService.update(q -> q
                .eq(Contract::getId, businessId)
                .set(Contract::getStatus, FlowStatusEnum1.REJECT.getKey())//20为驳回
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

}
