package com.dayou.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.dayou.common.BaseEntity;
import com.dayou.dto.*;
import com.dayou.entity.*;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.AssetsProductionMapper;
import com.dayou.mapper.OrderFundMapper;
import com.dayou.mapper.ProductionFundMapper;
import com.dayou.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dayou.utils.LoginContext;
import com.dayou.vo.AssetsProductionFundVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;

import org.springframework.transaction.annotation.Transactional;

import static com.dayou.enums.MainBusinessEnum.ASSET_BUSINESS;
import static com.dayou.enums.ProductionEnum.STATEMENT;

/**
 * <p>
 * 资产产品表 服务实现类
 * </p>
 *
 * @author GouGengquan
 * @since 2024-03-28
 */
@DS("mbs")
@Service
public class AssetsProductionServiceImpl extends ServiceImpl<AssetsProductionMapper, AssetsProduction> implements IAssetsProductionService {

    @Autowired
    private AssetsProductionMapper assetsProductionMapper;

    @Autowired
    private IAssetsService assetsService;

    @Autowired
    private IBusinessProductionService businessProductionService;

    @Autowired
    private IOrderFundService orderFundService;

    @Autowired
    private IProductionOutWarehouseService productionOutWarehouseService;

    @Autowired
    private IProductionFundService productionFundService;

    @Autowired
    private IAssetsEvaluationTargetService assetsEvaluationTargetService;

    @Autowired
    private IBusinessProductionChoiceLogService choiceLogService;

    @Autowired
    private IFinanceClaimService financeClaimService;

    @Autowired
    private ProductionFundMapper productionFundMapper;

    @Autowired
    private OrderFundMapper orderFundMapper;

    @Autowired
    private IOrderFundAllotService orderFundAllotService;

    /**
     * 根据资产业务id查询资产业务产品
     *
     * @param id 资产业务id
     * @return List<AssetsProduction>
     */
    @Override
    public List<AssetsProduction> getAroductionByAssetsId(Long id) {
        return this.list(new LambdaQueryWrapper<AssetsProduction>().eq(AssetsProduction::getBusinessId, id));
    }

    @Override
    @SuppressWarnings("unchecked")
    public Page<AssetsProduction> selectPage(Page page, AssetsProduction assetsProduction) {
        return this.page(page, new QueryWrapper<AssetsProduction>(assetsProduction));
    }


    @Override
    public AssetsProduction detail(Long id) {
        return this.getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(AssetsProduction assetsProduction) {
        this.save(assetsProduction);
        // 选择产品时给当前选择产品的评估对象添加选择产品记录
        List<BusinessProductionChoiceLog> choiceLogList = new ArrayList<>();
        for (Long targetId : assetsProduction.getTargetIdList()) {
            BusinessProductionChoiceLog choiceLog = new BusinessProductionChoiceLog();
            choiceLog.setBusinessType("ASSET_BUSINESS");
            choiceLog.setProductionType(assetsProduction.getProductionType());
            choiceLog.setBusinessId(assetsProduction.getBusinessId());
            choiceLog.setTargetId(targetId);
            choiceLog.setPrintCount(assetsProduction.getPrintCount());
            choiceLog.setProductionId(assetsProduction.getId());
            choiceLogList.add(choiceLog);
        }
        return choiceLogService.saveBatch(choiceLogList);
    }

    /**
     * 产品信息更新
     * @param assetsProduction prod
     * @return Boolean
     */
    @Override
    public Boolean update(AssetsProduction assetsProduction) {
        return this.updateById(assetsProduction);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateChoice(AssetsProduction assetsProduction) {
        // 更新选择产品时给当前选择产品的评估对象更新选择产品记录
        List<BusinessProductionChoiceLog> choiceLogList = new ArrayList<>();
        for (Long targetId : assetsProduction.getTargetIdList()) {
            BusinessProductionChoiceLog choiceLog = choiceLogService.getOne(new LambdaQueryWrapper<BusinessProductionChoiceLog>()
                    .eq(BusinessProductionChoiceLog::getBusinessType, "ASSET_BUSINESS")
                    .eq(BusinessProductionChoiceLog::getBusinessId, assetsProduction.getBusinessId())
                    .eq(BusinessProductionChoiceLog::getTargetId, targetId)
                    .eq(BaseEntity::getDeleted, 0)
                    .eq(BusinessProductionChoiceLog::getTakeNoStatus, 0));
            choiceLog.setProductionId(assetsProduction.getId());
            choiceLog.setProductionType(assetsProduction.getProductionType());
            choiceLog.setPrintCount(assetsProduction.getPrintCount());
            choiceLogList.add(choiceLog);
        }
        choiceLogService.updateBatchById(choiceLogList);
        return this.updateById(assetsProduction);
    }

    @Override
    public Boolean delete(Long id) {
        //逻辑删除
        return this.removeById(id);
    }

    /**
     * 根据业务id获取产品信息类型集合
     *
     * @param businessId 资产业务id
     * @return List<String>
     */
    public List<String> getProductionTypes(Long businessId) {
        return assetsProductionMapper.getProductionTypes(businessId);
    }

    /**
     * 根据业务id获取已选择产品
     *
     * @param businessId 资产业务id
     * @return AssetsProduction
     */
    @Override
    public AssetsProduction getProductionByBusinessId(Long businessId) {
        return assetsProductionMapper.getProductionByBusinessId(businessId);
    }

    /**
     * 撰写产品信息
     *
     * @param assetsProduction 产品信息字段
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean writeAssetsProduction(AssetsProduction assetsProduction) {
        int count = this.count(new LambdaQueryWrapper<AssetsProduction>().select(AssetsProduction::getCreateProductionDate).eq(AssetsProduction::getProductionNo, assetsProduction.getProductionNo())
                .eq(AssetsProduction::getId, assetsProduction.getId()));
        if (count > 0) {
            return null;
        }
        // 生成产品二维码
        assetsProduction.setQrCode(businessProductionService.doCreateNormalCode(assetsProduction.getProductionType(), assetsProduction.getProductionNo()));
        // 新增产品收款信息
        if (!assetsProduction.getProductionType().equals(STATEMENT.getCode())) {
            addAssetsProShouldAmount(assetsProduction);
        }
        return assetsProductionMapper.writeAssetsProduction(assetsProduction);
    }

    /**
     * 根据业务id与产品号获取资产产品详细信息
     *
     * @param dto 查询dto
     * @return AssetsProduction
     */
    @Override
    public AssetsProduction getAssetsProductionDetail(AssetsProductionDetailDTO dto) {
        return this.getOne(new LambdaQueryWrapper<AssetsProduction>().eq(AssetsProduction::getBusinessId, dto.getBusinessId()).eq(AssetsProduction::getProductionNo, dto.getProductionNo()));
    }

    /**
     * 根据业务id与产品号查询产品信息
     *
     * @param aProListSelectDTO 查询dto
     * @return List<AssetsProduction>
     */
    @Override
    public List<AssetsProduction> getProductionList(AProListSelectDTO aProListSelectDTO) {
        return assetsProductionMapper.getProductionList(aProListSelectDTO);
    }

    /**
     * 根据业务id与产品号查询该产品是否已有提交的流程实例信息
     *
     * @param aProListSelectDTO 查询dto
     * @return Integer
     */
    @Override
    public Integer getInatanceCount(AProListSelectDTO aProListSelectDTO) {
        return assetsProductionMapper.getInatanceCount(aProListSelectDTO);
    }

    /**
     * 根据业务id与产品号集合获取每个产品是否有提交过的流程实例信息
     *
     * @return List<Integer>
     */
    @Override
    public List<Integer> getInatanceCountList(AProListSelectDTO aProListSelectDTO) {
        List<Integer> countList = new ArrayList<>();
        for (String productionNo : aProListSelectDTO.getProductionNos()) {
            countList.add(assetsProductionMapper.getInatanceCountByIdAndProNo(aProListSelectDTO.getBusinessId(), productionNo));
        }
        return countList;
    }

    /**
     * 产品出入库
     *
     * @param wareHouseDTO 出入库信息dto
     * @return Boolean
     */
    @Override
    public Boolean assetsProRepertory(AssetsProWareHouseDTO wareHouseDTO) {
        AssetsProduction assetsProduction = this.getOne(new LambdaQueryWrapper<AssetsProduction>()
                .select(BaseEntity::getId, AssetsProduction::getRepertoryState,
                        AssetsProduction::getProductionNo,
                        AssetsProduction::getBusinessId,
                        AssetsProduction::getProductionType)
                .eq(BaseEntity::getId, wareHouseDTO.getProductionId())
                .eq(BaseEntity::getDeleted, Boolean.FALSE));
        if (ObjectUtil.isNull(assetsProduction)) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "产品不存在，操作失败。");
        } else if (!assetsProduction.getProductionNo().equals(wareHouseDTO.getProductionNo())) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "操作的产品报告号与当前操作的产品报告号不一致，请检查。");
        } else if (!assetsProduction.getProductionType().equals(wareHouseDTO.getProductionType())) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "操作的产品类型与当前操作的产品类型不符，请检查。");
        } else {
            // true出库,false入库
            if (wareHouseDTO.getRepertoryState()) { // 出库
                if (ObjectUtil.isNull(assetsProduction.getRepertoryState())) {
                    ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "产品还未入库，无法出库。");
                } else if (assetsProduction.getRepertoryState()) {
                    ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "产品还已出库，无需出库。");
                }
//                OrderFund orderFund = orderFundService.getOne(new LambdaQueryWrapper<OrderFund>()
//                        .select(BaseEntity::getId, OrderFund::getRealAmount)
//                        .eq(OrderFund::getBusinessId, wareHouseDTO.getBusinessId())
//                        .eq(OrderFund::getBusinessType, ASSET_BUSINESS.getCode()));
                ProductionFund productionFund = productionFundService.getOne(new LambdaQueryWrapper<ProductionFund>()
                        .select(BaseEntity::getId, ProductionFund::getRealAmount)
                        .eq(ProductionFund::getProductionNo, wareHouseDTO.getProductionNo())
                        .eq(ProductionFund::getBusinessType, ASSET_BUSINESS.getCode()));
                // 非意见书,且实收款未认领(产品实收款为NULL)
                if (!assetsProduction.getProductionType().equals(STATEMENT.name()) && ObjectUtil.isNull(productionFund.getRealAmount())) {
                    int passCount = productionOutWarehouseService.count(new LambdaQueryWrapper<ProductionOutWarehouse>()
                            .select(ProductionOutWarehouse::getDepartmentCheckState)
                            .eq(ProductionOutWarehouse::getReportNo, wareHouseDTO.getProductionNo())
                            .eq(ProductionOutWarehouse::getBusinessType, "ASSET_BUSINESS")
                            .eq(ProductionOutWarehouse::getDepartmentCheckState, "审核通过")
                            .eq(BaseEntity::getDeleted, 0));
                    // 判断出库审核是否通过
                    if (passCount < 1) { // 不通过提示
                        ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "不满足出库条件，该产品需客户经理申请产品出库通过后方可出库。");
                    } else { // 通过则出库
                        return this.update(new LambdaUpdateWrapper<AssetsProduction>()
                                .set(AssetsProduction::getRepertoryState, 1)
                                .set(AssetsProduction::getRepertoryOutTime, new Date())
                                .eq(BaseEntity::getId, wareHouseDTO.getProductionId())
                                .eq(AssetsProduction::getProductionNo, wareHouseDTO.getProductionNo()));
                    }
                } else { // 意见书可以直接出库
                    return this.update(new LambdaUpdateWrapper<AssetsProduction>()
                            .set(AssetsProduction::getRepertoryState, 1)
                            .set(AssetsProduction::getRepertoryOutTime, new Date())
                            .eq(BaseEntity::getId, wareHouseDTO.getProductionId())
                            .eq(AssetsProduction::getProductionNo, wareHouseDTO.getProductionNo()));
                }
            } else { // 入库
                return this.update(new LambdaUpdateWrapper<AssetsProduction>()
                        .set(AssetsProduction::getRepertoryState, 0)
                        .set(AssetsProduction::getRepertoryInTime, new Date())
                        .eq(BaseEntity::getId, wareHouseDTO.getProductionId())
                        .eq(AssetsProduction::getProductionNo, wareHouseDTO.getProductionNo()));
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 根据资产产品id更新文件路由信息
     *
     * @param assetsProduction 产品信息dto
     * @return Boolean
     */
    @Override
    public Boolean updateProductionFileInfo(AssetsProduction assetsProduction) {
        return assetsProductionMapper.updateProductionFileInfo(assetsProduction);
    }

    /**
     * 获取产品实收款
     *
     * @param productionNo 产品号
     * @return BigDecimal
     */
    @Override
    public BigDecimal getProductionRealAmount(String productionNo) {
        return assetsProductionMapper.getProductionRealAmount(productionNo);
    }

    /**
     * 产品标记送达
     *
     * @param productionNo 产品号
     * @return Boolean
     */
    @Override
    public Boolean markDelivery(String productionNo) {
        return assetsProductionMapper.markDelivery(productionNo);
    }

    /**
     * 查找实收款认领产品列表
     *
     * @param apFundSelectDTO 查询dto
     * @return List<AssetsProductionFundVo>
     */
    @Override
    public Page<AssetsProductionFundVo> getAssetsProductionFundVoList(Page page, APFundSelectDTO apFundSelectDTO) {
        return assetsProductionMapper.getAssetsProductionFundVoList(page, apFundSelectDTO, LoginContext.getCurrentUserId());
    }

    /**
     * 查找实收款认领订单列表
     *
     * @param apFundSelectDTO 查询dto
     * @return List<AssetsProductionFundVo>
     */
    @Override
    public Page<AssetsProductionFundVo> getAssetsOrderFundVoList(Page page, APFundSelectDTO apFundSelectDTO) {
        return assetsProductionMapper.getAssetsOrderFundVoList(page, apFundSelectDTO, LoginContext.getCurrentUserId());
    }

    /**
     * 认领实收款到 产品
     *
     * @param claimOrders 认领信息
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean doAllotRealAmountToProd(List<OrderReportDTO> claimOrders) {
        if (CollectionUtil.isNotEmpty(claimOrders)) {
            //先校验各订单此次认领金额之和是否大于这笔实收款的剩余金额
            Long financeFundId = claimOrders.get(0).getFinanceFundId();
            BigDecimal residueAmount = financeClaimService.checkFinanceFound(financeFundId);
            BigDecimal thisTimeTotalAmount = claimOrders.stream().map(OrderReportDTO::getThisTimeAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (thisTimeTotalAmount.compareTo(residueAmount) > 0) {
                ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "本次订单认领之和大于实收款剩余金额，请检查后再认领。");
                return Boolean.FALSE;
            }

            for (OrderReportDTO orderReportDTO : claimOrders) {
                BigDecimal thisTimeAmount = orderReportDTO.getThisTimeAmount();
                if (thisTimeAmount == null || thisTimeAmount.compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                // 更新产品实收款
                productionFundMapper.updateRealAmount(orderReportDTO.getProductionFundId(), thisTimeAmount);
                // 更新订单实收款
                orderFundMapper.updateRealAmount(orderReportDTO.getOrderFundId(), thisTimeAmount);
                //更新订单折扣比例
                orderFundMapper.updateDiscountByOrderIdAfter(orderReportDTO.getOrderFundId());

                //插入订单认领记录流水表
                FinanceClaim financeClaim = new FinanceClaim();
                Long userId = LoginContext.getCurrentUserId();
                financeClaim.setClaimUserId(userId);
                financeClaim.setRealFundId(financeFundId);
                financeClaim.setOrderFundId(orderReportDTO.getOrderFundId());
                financeClaim.setClaimAmount(thisTimeAmount);
                financeClaim.setClaimDatetime(new Date());
                financeClaim.setProductionFundId(orderReportDTO.getProductionFundId());
                financeClaimService.add(financeClaim);
            }
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 根据订单收款id获取产品收款信息
     * @param orderFundId 资产订单收款id
     * @return List<ReportDTO>
     */
    @Override
    public List<ReportDTO> getProductionFundByOrderFundId(Long orderFundId) {
        return assetsProductionMapper.getProductionFundByOrderFundId(orderFundId);
    }

    /**
     * 资产分配订单实收款到产品
     *
     * @param orderReportDTO 分配信息
     * @return Boolean
     */
    @Override
    public Boolean allotOrderRealAmountToProduction(OrderReportDTO orderReportDTO) {
        List<ReportDTO> reports = orderReportDTO.getReports();
        Long orderFundId = orderReportDTO.getOrderFundId();
        BigDecimal residueAmount = orderFundMapper.residueNotAllotAmount(orderFundId);
        BigDecimal totalAmount = reports.stream().map(ReportDTO::getThisTimeAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (orderReportDTO.getRealAmount() == null) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "该订单还未认领实收款，请先认领实收款后再分配。");
        }
        if (totalAmount.compareTo(residueAmount) > 0) {
            ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR, "产品分配金额不能大于订单未分配金额，请检查后再试。");
        }
        if (CollectionUtil.isNotEmpty(reports)) {
            for (ReportDTO reportDTO : reports) {
                Long productionFundId = reportDTO.getProductionFundId();
                if (reportDTO.getThisTimeAmount() == null || reportDTO.getThisTimeAmount().compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                productionFundMapper.updateRealAmount(productionFundId, reportDTO.getThisTimeAmount());
                //分配记录表
                OrderFundAllot orderFundAllot = new OrderFundAllot();
                orderFundAllot.setProductionFundId(productionFundId);
                orderFundAllot.setOrderFundId(orderFundId);
                orderFundAllot.setAllotAmount(reportDTO.getThisTimeAmount());
                orderFundAllotService.save(orderFundAllot);
            }
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 产品归档
     *
     * @param saveFileDate 归档时间
     */
    @Override
    public void prodSaveFile(Date saveFileDate, String productionNo) {
        assetsProductionMapper.prodSaveFile(saveFileDate, productionNo);
    }

    @Override
    public List<Long> getReportByAssetsId(Long id) {
        return assetsProductionMapper.getReportByAssetsId(id);
    }

    @Override
    public void updateSigner(String jsonString, Long reportId) {
        this.update(new LambdaUpdateWrapper<AssetsProduction>()
                .set(AssetsProduction::getSignatory,jsonString).eq(BaseEntity::getId,reportId));
    }

    /**
     * 新增订单产品收款信息
     *
     * @param assetsProduction 资产产品信息
     */
    public void addAssetsProShouldAmount(AssetsProduction assetsProduction) {
        // 根据报告号获取评估对象信息
        List<AssetsEvaluationTarget> targetList = assetsEvaluationTargetService.list(new LambdaQueryWrapper<AssetsEvaluationTarget>()
                .select(AssetsEvaluationTarget::getTotalAssetCarryingAmount)
                .eq(AssetsEvaluationTarget::getReportNo, assetsProduction.getProductionNo()));
        if (ObjectUtil.isNotNull(targetList) && ObjectUtil.isNotEmpty(targetList)) {
            // 使用流计算审核价格的总和
            BigDecimal total = targetList.stream()
                    .map(AssetsEvaluationTarget::getTotalAssetCarryingAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 由于评估值单位为 万元,标准收费为 元,所以此处 评估值 * 10000 用于后续计算标准收费
            total = total.multiply(BigDecimal.valueOf(10000));

            // 新增产品收款信息
            OrderFund orderFund = orderFundService.getOne(new LambdaQueryWrapper<OrderFund>()
                    .select(OrderFund::getId)
                    .eq(OrderFund::getBusinessId, assetsProduction.getBusinessId())
                    .eq(OrderFund::getBusinessType, "ASSET_BUSINESS"));
            ProductionFund productionFund = new ProductionFund();
            productionFund.setBusinessType(ASSET_BUSINESS.getCode());
            productionFund.setBusinessId(assetsProduction.getBusinessId());
            productionFund.setOrderFundId(orderFund.getId());
            productionFund.setEvaluateAmount(total);
            productionFund.setProductionNo(assetsProduction.getProductionNo());
            productionFund.setProductionType(assetsProduction.getProductionType());
            productionFundService.add(productionFund);
        }
    }
}
