package com.jwipc.finance.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.SapResposeBody;
import com.jwipc.constant.DictCode;
import com.jwipc.constant.SignProcessType;
import com.jwipc.contract.base.ContractSendSignClientDTO;
import com.jwipc.contract.base.ContractSendSignResultClientDTO;
import com.jwipc.contract.client.ContractSignClient;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.CostAccountStatementConvert;
import com.jwipc.finance.convert.CostAccountStatementDetailConvert;
import com.jwipc.finance.dto.*;
import com.jwipc.finance.entity.*;
import com.jwipc.finance.logic.CostAccountStatementLogic;
import com.jwipc.finance.model.po.*;
import com.jwipc.finance.model.query.CostAccountStatementQuery;
import com.jwipc.finance.service.*;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.prop.SysProp;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierContactsDTO;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.*;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.DigitalSealBusinessDetailParamClientDTO;
import com.jwipc.sys.client.dto.EmailTmpSingleSendDTO;
import com.jwipc.sys.client.dto.ProductInfoDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author shenyang.ou
 * @date 2025/11/3 17:56
 * @desc
 */
@Service
@RequiredArgsConstructor
public class CostAccountStatementLogicImpl implements CostAccountStatementLogic {
    private final CostAccountStatementConvert costAccountStatementConvert;
    private final CostAccountStatementDetailConvert costAccountStatementDetailConvert;
    private final ICostAccountStatementService costAccountStatementService;
    private final IPaymentCodApplyDetailService paymentCodApplyDetailService;
    private final IPaymentStatementFilterConfigService paymentStatementFilterConfigService;
    private final EmailSendClient emailSendClient;
    private final SysProp sysProp;
    private final ICostAccountStatementApproveService costAccountStatementApproveService;
    private final ICostInvoicedApplyService costInvoicedApplyService;
    private final ICostAccountStatementDetailService costAccountStatementDetailService;
    private final IReceiveVoucherService receiveVoucherService;
    private final SequenceClient sequenceClient;
    private final DictClient dictClient;
    private final SupplierClient supplierClient;
    private final ProductClient productClient;
    private final DigitalSealBusinessDetailClient digitalSealBusinessDetailClient;
    private final ContractSignClient contractSignClient;
    private final IPaymentCodApplyService paymentCodApplyService;
    private final SysConfigClient sysConfigClient;

    @Override
    public CostAccountStatementDTO getById(Long id) {
        CostAccountStatementPO costAccountStatement = costAccountStatementService.getPoById(id);
        CostAccountStatementDTO accountStatementDTO = costAccountStatementConvert.po2DTO(costAccountStatement);
//        if ("CNY".equals(accountStatementDTO.getCurrencyCode())){
//            accountStatementDTO.setOriginalCurrency(accountStatementDTO.getTaxAmount().add(accountStatementDTO.getOriginalCurrency()));
//        }
        return accountStatementDTO;
    }

    @Override
    public PageView findByPage(CostAccountStatementQuery query) {
        final Page<CostAccountStatement> dbPage = PageUtil.toPage(query);
        query.setBusinessTypeCode(SignProcessType.COST_ACCOUNT_STATEMENT.getBusinessNo());
        List<CostAccountStatementPO> accountStatementPOS = costAccountStatementService.findPageByQuery(dbPage, query);
        List<CostAccountStatementDTO> accountStatementDTOS = costAccountStatementConvert.po2PageListDTO(accountStatementPOS);
        accountStatementDTOS.forEach(accountStatementDTO -> {
            //增加对账单是否付款判断， 2024-12-23 邓京术
            List<PaymentCodApply> paymentCodApplyList = paymentCodApplyService.findAppDetailByAccountStatementNo(accountStatementDTO.getAccountStatementNo());
            //需要计算实际未付金额
            //对账单含税金额 应该与所有的已请款的金额累加相等，且付款完成 就计算为已付款状态为是
            BigDecimal taxAmount = accountStatementDTO.getActualUnpaidAmount();
            if (taxAmount==null){
                return;
            }
            BigDecimal totalPay = BigDecimal.ZERO;
            for (PaymentCodApply apply : paymentCodApplyList) {
                if (null != apply && null != apply.getStatus() && apply.getStatus() == 5) {
                    //付款申请里面的本次申请金额
                    totalPay = totalPay.add(apply.getActualityPayMoney() == null?BigDecimal.ZERO:apply.getActualityPayMoney());
                }
            }
            if (totalPay.floatValue() == 0f || totalPay.floatValue() != taxAmount.floatValue()) {
                accountStatementDTO.setPaymentStatus("否");
            } else {
                accountStatementDTO.setPaymentStatus("是");
            }
            accountStatementDTO.setSignFileStatus(ObjectUtil.isNotNull(accountStatementDTO.getSignStatus())?1:0);
        });
        return PageUtil.getPV(accountStatementDTOS, dbPage.getTotal());
    }

    @Override
    public List<CostAccountStatementDTO> listAll(CostAccountStatementQuery query) {
        List<CostAccountStatementPO> accountStatementPOS = costAccountStatementService.findPageByQuery(null, query);
        return costAccountStatementConvert.po2PageListDTO(accountStatementPOS);
    }

    @Override
    @Transactional
    public void saveOrUpdate(CostAccountStatementParamDTO param) {
        if (param.getId() == null) {
            param.setAccountStatementNo(sequenceClient.createSequenceNo("cost_account_statement_no"));
            param.setStatus(1);
            param.setCreateTime(LocalDateTime.now());
            param.setCreateUserId(LoginUtil.getUserId());
            param.setCreateUserCode(LoginUtil.getAccount());
            param.setCreateUserName(LoginUtil.getName());
        } else {
            param.setUpdateTime(LocalDateTime.now());
            param.setStatus(1);
            param.setUpdateUserId(LoginUtil.getUserId());
            param.setUpdateUserCode(LoginUtil.getAccount());
            param.setUpdateUserName(LoginUtil.getName());
            //删除明细
            costAccountStatementDetailService.remove(Wrappers.lambdaQuery(CostAccountStatementDetail.class).eq(CostAccountStatementDetail::getAsId,param.getId()));
        }
        param.setDifferenceAmount(param.getDomesticTaxTotalAmount());
        param.setNotTaxAmount(param.getTaxAmount().subtract(param.getDomesticTaxTotalAmount()));
        //保存主数据
        CostAccountStatement costAccountStatement = costAccountStatementConvert.DTO2Entity(param);
        costAccountStatementService.saveOrUpdate(costAccountStatement);
        final List<CostAccountStatementDetailDTO> costAccountStatementDetailDTOS = param.getDetailList();
        AtomicInteger index = new AtomicInteger(1);
        costAccountStatementDetailDTOS.forEach(asd -> {
            //判断对账明细中是否存在已经使用过的物料凭证
            CostAccountStatementDetail detail = costAccountStatementDetailService.getOne(Wrappers.lambdaQuery(CostAccountStatementDetail.class).eq(CostAccountStatementDetail::getCostMatchingPaymentNoticeRelationId,asd.getCostMatchingPaymentNoticeRelationId()).eq(CostAccountStatementDetail::getDeleteFlag,0).last(" limit 1"));
            if (ObjectUtil.isNotNull(detail)){
                throw new DaoException("委托单号："+asd.getCode()+",已创建过对账单，无法继续创建");
            }
            asd.setId(null);
            asd.setAsNo(param.getAccountStatementNo());
            String itemNo = StringUtils.leftPad(String.valueOf(index.get()*10), 5, "0");
            asd.setItemNo(itemNo);
            asd.setCreateUserId(LoginUtil.getUserId());
            asd.setCreateUserCode(LoginUtil.getAccount());
            asd.setCreateUserName(LoginUtil.getName());
            asd.setCreateTime(LocalDateTime.now());
            asd.setAsId(costAccountStatement.getId());
            asd.setAsNo(costAccountStatement.getAccountStatementNo());
            index.getAndIncrement();
        });
        costAccountStatementDetailService.saveBatch(costAccountStatementDetailConvert.dto2EntityList(costAccountStatementDetailDTOS));
    }

    @Override
    @Transactional
    public void dataDel(String ids, Integer type) {
        //校验对账单明细是否被使用
        // 1.检查待删除的数据是否可以删除
        // 2.更新对账单删除标识
        // 3.更新对账单明细删除标识
        // 4.更新对账单扣款关系删除标识并更新扣款主表使用状态
        // 5.更新对账单返利关系删除标识并更新返利主表使用状态
        final List<Long> idList = JSONArray.parseArray(ids, Long.class);
        List<CostAccountStatement> list = costAccountStatementService.checkAccountStatementStatus(idList);
        for(CostAccountStatement as: list){
            CostInvoicedApply invoicedApply = costInvoicedApplyService.getOne(Wrappers.lambdaQuery(CostInvoicedApply.class).eq(CostInvoicedApply::getAccountStatementId,as.getId()).last(" limit 1"));
            if (ObjectUtil.isNotNull(invoicedApply)){
                throw new DaoException("对账单: " + as.getAccountStatementNo() + "不能被删除，已被开票申请："+invoicedApply.getInvoiceApplyNo()+"使用");
            }
            if (type!=null&&type==1){
                as.setUpdateTime(LocalDateTime.now());
                as.setUpdateUserId(LoginUtil.getUserId());
                as.setUpdateUserCode(LoginUtil.getAccount());
                as.setUpdateUserName(LoginUtil.getName());
                as.setDeleteFlag(1);
            }else {
                if(1 == as.getStatus() || 3 == as.getStatus() || 9 == as.getStatus() || 8 == as.getStatus()){
                    as.setUpdateTime(LocalDateTime.now());
                    as.setUpdateUserId(LoginUtil.getUserId());
                    as.setUpdateUserCode(LoginUtil.getAccount());
                    as.setUpdateUserName(LoginUtil.getName());
                    as.setDeleteFlag(1);
                }else {
                    throw new DaoException("对账单: " + as.getAccountStatementNo() + ", 当前状态不能被删除");
                }
            }
        }

        if(CollectionUtils.isNotEmpty(list)){
            if(!costAccountStatementService.updateBatchById(list)){
                throw new DaoException("对账单删除失败, 请联系管理员");
            }
        }

        if(!costAccountStatementDetailService.deleteByAsIdList(idList)){
            throw new DaoException("对账单明细删除失败, 请联系管理员");
        }

//        accountStatementAttachmentLogic.deleteByAsIdList(idList);

//        for (Long id : idList){
//            AccountStatement accountStatement = accountStatementService.getById(id);
//            List<AccountStatementDetail> asdList = accountStatementDetailService.list(Wrappers.lambdaQuery(AccountStatementDetail.class).eq(AccountStatementDetail::getAsId,id));
//            AccountStatementToSapDTO accountStatementToSapDTO = makeAccountStatementSapData(1,"X",accountStatement,null,asdList,null);
//            SapResposeBody sapResposeBody = accountStatementSapClient.syncAccountStatement(accountStatementToSapDTO);
//            if (StringUtils.isEmpty(sapResposeBody.getES_RET().getCODE())||sapResposeBody.getES_RET().getCODE().equals(RestCode.SAP_ERROR.getCode())) {
//                throw new DaoException("SAP接口报错：" + sapResposeBody.getES_RET().getMSG());
//            }
//        }
    }

    @Override
    @Transactional
    public void submitConfirm(String ids) {
        final List<Long> idList = JSONArray.parseArray(ids, Long.class);
        List<CostAccountStatement> list = costAccountStatementService.checkAccountStatementStatus(idList);
        for(CostAccountStatement as: list){
            if(1 == as.getStatus() || 3 == as.getStatus()){
                as.setUpdateTime(LocalDateTime.now());
                as.setUpdateUserId(LoginUtil.getUserId());
                as.setUpdateUserCode(LoginUtil.getAccount());
                as.setUpdateUserName(LoginUtil.getName());
                as.setStatus(2);
            }else {
                throw new DaoException("对账单: " + as.getAccountStatementNo() + ", 当前状态不能被提交");
            }
        }

        if(CollectionUtils.isNotEmpty(list)){
            if(!costAccountStatementService.updateBatchById(list)){
                throw new DaoException("对账单状态更新失败, 请联系管理员");
            }
        }
//        for (Long id : idList){
//            CostAccountStatement accountStatement = costAccountStatementService.getById(id);
//            List<CostAccountStatementDetail> asdList = costAccountStatementDetailService.list(Wrappers.lambdaQuery(CostAccountStatementDetail.class).eq(CostAccountStatementDetail::getAsId,id));
//            AccountStatementToSapDTO accountStatementToSapDTO = makeAccountStatementSapData(2,"",accountStatement,null,asdList,null);
//            SapResposeBody sapResposeBody = accountStatementSapClient.syncAccountStatement(accountStatementToSapDTO);
//            if (StringUtils.isEmpty(sapResposeBody.getES_RET().getCODE())||sapResposeBody.getES_RET().getCODE().equals(RestCode.SAP_ERROR.getCode())) {
//                throw new DaoException("SAP接口报错：" + sapResposeBody.getES_RET().getMSG());
//            }
//        }
    }


    @Override
    public Map<String, Object> printStatement(Long id) {
        Map<String, Object> map = new HashMap<>();
        CostAccountStatementDTO  accountStatementDTO = this.getById(id);
        //字典赋值
        DictDTO dictDTO = dictClient.getDictByTypeAndCode(DictCode.PAYMENT_TERMS.getCode(), accountStatementDTO.getPaymentTermCode());
        if (ObjectUtil.isNotNull(dictDTO)){
            accountStatementDTO.setPaymentTermName(dictDTO.getName());
        }

        map.put("agencyFeeRate",sysConfigClient.getTextConfig("agencyFeeRate"));
        //查询供应商品类表中的承兑期限放到购销合同模板上

        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        accountStatementDTO.setCreateTimeStr(accountStatementDTO.getCreateTime().format(formatter1));
        if (Objects.nonNull(accountStatementDTO.getFinanceConfirmTime())){
            accountStatementDTO.setFinanceConfirmTimeStr(accountStatementDTO.getFinanceConfirmTime().format(formatter1));
        }
        if (Objects.nonNull(accountStatementDTO) &&
                Objects.nonNull(accountStatementDTO.getAccountStatementYear())
                && Objects.nonNull(accountStatementDTO.getAccountStatementMonth())){
            YearMonth yearMonth = YearMonth.of(Integer.parseInt(accountStatementDTO.getAccountStatementYear()),
                    Integer.parseInt(accountStatementDTO.getAccountStatementMonth()));
            LocalDate firstDayOfMonth = yearMonth.atDay(1);
            LocalDate lastDayOfMonth = yearMonth.atEndOfMonth();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
//            accountStatementDTO.setAccountStatementPeriod(formatter.format(firstDayOfMonth)+"到"+formatter.format(lastDayOfMonth));
            accountStatementDTO.setAccountStatementPeriod(DateUtil.format(accountStatementDTO.getInStockStartDate(),"yyyy.MM.dd")+"到"+DateUtil.format(accountStatementDTO.getInStockEndDate(),"yyyy.MM.dd"));
        }
        map.put("accountStatement",accountStatementDTO);
//        model.addAttribute("accountStatement", accountStatementDTO);
        //人民币含税，非人民币不含税
        if ("CNY".equalsIgnoreCase(accountStatementDTO.getCurrencyCode())) {
            accountStatementDTO.setIncludeTax("含税");
        } else {
            accountStatementDTO.setIncludeTax("不含税");
            accountStatementDTO.setToBeInvoiced("(待开票)");
        }
        SupplierContactsDTO defaultContact = supplierClient.getDefaultContact(accountStatementDTO.getSupplierCode(), "4");
        SupplierDTO supplierDTO = supplierClient.getSupplierByCode(accountStatementDTO.getSupplierCode());
//        model.addAttribute("supplierInvoiced", defaultContact);
        map.put("supplier",supplierDTO);
        map.put("supplierInvoiced",defaultContact);

//        model.addAttribute("data", accountStatementDTO);
        map.put("data",accountStatementDTO);

        //明细数据
        List<CostAccountStatementDetailPO> statementItemDTOS = costAccountStatementDetailService.findByStatementId(id);

        Map<String,String> materiaNameMap = new HashMap<>();

        if (CollUtil.isNotEmpty(statementItemDTOS)){

        }
        BigDecimal taxAmountTotal = BigDecimal.ZERO;
        BigDecimal tariffPriceTotal = BigDecimal.ZERO;
        BigDecimal valueAddedTaxPriceTotal = BigDecimal.ZERO;
        BigDecimal agencyFeePriceTotal = BigDecimal.ZERO;
        BigDecimal domesticFeePriceTotal = BigDecimal.ZERO;
        BigDecimal overseasFeePriceTotal = BigDecimal.ZERO;
        BigDecimal feeTaxAmountPriceTotal = BigDecimal.ZERO;
        BigDecimal freightPriceTotal = BigDecimal.ZERO;
        BigDecimal freightTaxAmountPriceTotal = BigDecimal.ZERO;
        BigDecimal otherFeePriceTotal = BigDecimal.ZERO;
        BigDecimal sum1Total = BigDecimal.ZERO;
        BigDecimal sum2Total = BigDecimal.ZERO;
        for (CostAccountStatementDetailPO po : statementItemDTOS) {
//            po.setTaxPriceStr(String.valueOf(po.getTaxPrice().setScale(5, RoundingMode.HALF_UP)));
            //设置最新的物料名称，如果物料名称有变化，则取最新的物料名称，打印的时候取短描述， 2024-08-14 邓京术
//            initMaterialName(po, materiaNameMap);

//            po.setSum1(po.getTariffPrice()
//                    .add(po.getValueAddedTaxPrice())
//                    .add(po.getAgencyFeePrice())
//                    .add(po.getDomesticFeePrice())
//                    .add(po.getOverseasFeePrice())
//                    .add(po.getFreightPrice())
//                    .add(po.getOtherFeePrice())
//            );
            po.setSum1(accountStatementDTO.getFreightAndMiscellaneousFeeIncludingTaxTotal().subtract(accountStatementDTO.getDomesticTaxTotalAmount())
            );

//            po.setSum2(po.getTariffPrice()
//                            .add(po.getFeeTaxAmountPrice())
//                            .add(po.getFreightTaxAmountPrice())
//            );
            po.setSum2(accountStatementDTO.getDomesticTaxTotalAmount()
            );
            taxAmountTotal = taxAmountTotal.add(po.getTaxAmount());
            tariffPriceTotal = tariffPriceTotal.add(po.getTariffPrice());
            valueAddedTaxPriceTotal = valueAddedTaxPriceTotal.add(po.getValueAddedTaxPrice());
            agencyFeePriceTotal = agencyFeePriceTotal.add(po.getAgencyFeePrice());
            domesticFeePriceTotal = domesticFeePriceTotal.add(po.getDomesticFeePrice());
            overseasFeePriceTotal = overseasFeePriceTotal.add(po.getOverseasFeePrice());
            feeTaxAmountPriceTotal = feeTaxAmountPriceTotal.add(po.getFeeTaxAmountPrice());
            freightPriceTotal = freightPriceTotal.add(po.getFreightPrice());
            freightTaxAmountPriceTotal = freightTaxAmountPriceTotal.add(po.getFreightTaxAmountPrice());
            otherFeePriceTotal = otherFeePriceTotal.add(po.getOtherFeePrice());
            sum1Total = sum1Total.add(po.getSum1());
            sum2Total = sum2Total.add(po.getSum2());
        }
        map.put("taxAmountTotal",taxAmountTotal);
        map.put("tariffPriceTotal",tariffPriceTotal);
        map.put("valueAddedTaxPriceTotal",valueAddedTaxPriceTotal);
        map.put("agencyFeePriceTotal",agencyFeePriceTotal);
        map.put("domesticFeePriceTotal",domesticFeePriceTotal);
        map.put("overseasFeePriceTotal",overseasFeePriceTotal);
        map.put("feeTaxAmountPriceTotal",feeTaxAmountPriceTotal);
        map.put("freightPriceTotal",freightPriceTotal);
        map.put("freightTaxAmountPriceTotal",freightTaxAmountPriceTotal);
        map.put("otherFeePriceTotal",otherFeePriceTotal);
        map.put("sum1Total",sum1Total);
        map.put("sum2Total",sum2Total);
        map.put("sum3Total",accountStatementDTO.getTaxAmount());


//        model.addAttribute("detailList",statementItemDTOS);
        map.put("detailList",statementItemDTOS);

        // 金额合计
        JSONObject jeHj = new JSONObject();
//        AtomicReference<BigDecimal> sumNotTaxAmount = new AtomicReference<>(BigDecimal.ZERO);
//        statementItemDTOS.forEach(item -> {
//            BigDecimal amount = Optional.ofNullable(item.getNotTaxAmount())
//                    .orElse(BigDecimal.ZERO);
//            BigDecimal currentSum = sumNotTaxAmount.get();
//            BigDecimal newSum = currentSum.add(amount).setScale(2, RoundingMode.HALF_UP);
//            sumNotTaxAmount.set(newSum);
//        });
//        BigDecimal sqje = statementItemDTOS.stream().map(StatementItemPO::getNotTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//        jeHj.put("sqje", statementItemDTOS.stream().map(StatementItemPO::getNotTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add));
//        AtomicReference<BigDecimal> sumTaxAmount = new AtomicReference<>(BigDecimal.ZERO);
//        statementItemDTOS.forEach(item -> {
//            BigDecimal amount = Optional.ofNullable(item.getTaxAmount())
//                    .orElse(BigDecimal.ZERO);
//            BigDecimal currentSum = sumTaxAmount.get();
//            BigDecimal newSum = currentSum.add(amount).setScale(2, RoundingMode.HALF_UP);
//            sumTaxAmount.set(newSum);
//        });


//        BigDecimal hsje = statementItemDTOS.stream().map(StatementItemPO::getTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//        jeHj.put("hsje",statementItemDTOS.stream().map(StatementItemPO::getTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add));
//        AtomicReference<BigDecimal> sumDiffTaxAmount = new AtomicReference<>(BigDecimal.ZERO);
//        statementItemDTOS.forEach(item -> {
//            BigDecimal amount = Optional.ofNullable(item.getDiffTaxAmount())
//                    .orElse(BigDecimal.ZERO);
//            BigDecimal currentSum = sumDiffTaxAmount.get();
//            BigDecimal newSum = currentSum.add(amount).setScale(2, RoundingMode.HALF_UP);
//            sumDiffTaxAmount.set(newSum);
//        });

//        BigDecimal hsce = statementItemDTOS.stream().map(StatementItemPO::getDiffTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//        jeHj.put("hsce",statementItemDTOS.stream().map(StatementItemPO::getDiffTaxAmount).filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add));

//        model.addAttribute("jeHj",jeHj);
        map.put("jeHj",jeHj);
        return map;
    }

    @Override
    public void saveSignFile(Long signFile, Long id) {
        DigitalSealBusinessDetailParamClientDTO paramClientDTO = DigitalSealBusinessDetailParamClientDTO.builder()
                .businessId(id)
                .businessTypeCode(SignProcessType.COST_ACCOUNT_STATEMENT.getBusinessNo())
                .fileId(signFile)
                .signStatus(2)
                .createTime(LocalDateTime.now())
                .build();
        digitalSealBusinessDetailClient.save(paramClientDTO);
    }

    @Override
    public void sendSign(String id) {
        CostAccountStatement accountStatement = costAccountStatementService.getById(id);
        ContractSendSignClientDTO contractSendSignClientDTO = ContractSendSignClientDTO.builder()
                .title(StrUtil.format("费用对账单：{}发起签署",accountStatement.getAccountStatementNo()))
                .companyCode(accountStatement.getCompanyCode())
                .supplierCode(accountStatement.getSupplierCode())
                .fileKey(accountStatement.getFileKey())
                .contractSignOrder("2")
                .build();
        ContractSendSignResultClientDTO resultClientDTO = contractSignClient.sendSignClient(contractSendSignClientDTO, SignProcessType.COST_ACCOUNT_STATEMENT);
        costAccountStatementService.update(new LambdaUpdateWrapper<CostAccountStatement>().set(CostAccountStatement::getSignFlowId,resultClientDTO.getSignFlowId())
                .set(CostAccountStatement::getSignStatus, resultClientDTO.getSignFlowStatus())
                .eq(CostAccountStatement::getId,id));
    }

    @Override
    public void revokeFinConfirm(Long asId, String revokeReason) {
        final CostAccountStatement statement = costAccountStatementService.getById(asId);
        if(null == statement){
            throw new DaoException("系统未找到相应的对账单信息");
        }
        if(7 != statement.getStatus()){
            throw new DaoException("对账单不能进行撤销操作, 请检查对账单状态");
        }

        // 1.撤销时对账单状态由7(待财务确认)变更为2(待采购确认)
        CostAccountStatement updateHead = new CostAccountStatement();
        updateHead.setId(statement.getId());
        updateHead.setStatus(2);
        updateHead.setUpdateUserId(LoginUtil.getUserId());
        updateHead.setUpdateUserCode(LoginUtil.getAccount());
        updateHead.setUpdateUserName(LoginUtil.getName());
        updateHead.setUpdateTime(LocalDateTime.now());
        costAccountStatementService.updateById(updateHead);

        // 2.记录撤销原因
        CostAccountStatementApprove approve = new CostAccountStatementApprove();
        approve.setAsId(statement.getId());
        approve.setAsNo(statement.getAccountStatementNo());
        approve.setApproveResult(2);
        approve.setApproveOpinion(revokeReason);
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 撤销只能由采购操作
        approve.setApproveNode(1);
        approve.setApproveTime(LocalDateTime.now());
        costAccountStatementApproveService.save(approve);
    }

    @Override
    public void purchaseApproveOperation(CostAccountStatementApproveDTO param) {
        CostAccountStatement head = costAccountStatementService.getById(param.getId());
        head.setUpdateTime(LocalDateTime.now());
        head.setUpdateUserId(LoginUtil.getUserId());
        head.setUpdateUserCode(LoginUtil.getAccount());
        head.setUpdateUserName(LoginUtil.getName());
        head.setPurchaseConfirmTime(LocalDateTime.now());
        head.setPurchaseConfirmUserId(LoginUtil.getUserId());
        if(0 == param.getApproveStatus()){
            // 数据状态 1:暂存对账单 2:待采购确认对账单 3:采购拒绝对账单 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认对账单 8:财务驳回对账单 9:对账单已确认
            head.setStatus(3);
        }else {
            // 变更对账单相关数据
            head.setStatus(7);
            if ("1100".equals(head.getCompanyCode())){
                head.setStatus(9);
            }
        }
        // 更新对账单主表信息
        if(!costAccountStatementService.updateById(head)){
            throw new DaoException("更新对账单主表数据失败, 请联系管理员");
        }
        // 2.记录原因
        CostAccountStatementApprove approve = new CostAccountStatementApprove();
        approve.setAsId(head.getId());
        approve.setAsNo(head.getAccountStatementNo());
        approve.setApproveResult(param.getApproveStatus());
        approve.setApproveOpinion(param.getApproveOpinion());
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 采购节点
        approve.setApproveNode(1);
        approve.setApproveTime(LocalDateTime.now());
        costAccountStatementApproveService.save(approve);
    }

    @Override
    public void financeApproveOperation(CostAccountStatementApproveDTO param) {
        CostAccountStatement head = costAccountStatementService.getById(param.getId());
        head.setUpdateTime(LocalDateTime.now());
        head.setUpdateUserId(LoginUtil.getUserId());
        head.setUpdateUserCode(LoginUtil.getAccount());
        head.setUpdateUserName(LoginUtil.getName());
        head.setFinanceConfirmTime(LocalDateTime.now());
        head.setFinanceConfirmUserId(LoginUtil.getUserId());
        if(0 == param.getApproveStatus()){
            // 数据状态 1:暂存对账单 2:待采购确认对账单 3:采购拒绝对账单 4:待推送OA审批 5:OA审批中 6:OA审批不通过 7:待财务确认对账单 8:财务驳回对账单 9:对账单已确认
            head.setStatus(8);
            // 更新对账单主表信息
            if(!costAccountStatementService.updateById(head)){
                throw new DaoException("更新对账单主表数据失败, 请联系管理员");
            }
            //财务驳回对账单，增加邮件提醒，  邮件收件人：供应商（(4)财务人员、(12)业务接口人、(5)业务经理）、对账采购组窗口
            SupplierContactsDTO emailBis = supplierClient.getDefaultContact(head.getSupplierCode(), "12");
            SupplierContactsDTO emailFin = supplierClient.getDefaultContact(head.getSupplierCode(), "4");
            SupplierContactsDTO emailJl = supplierClient.getDefaultContact(head.getSupplierCode(), "5");

            if (Objects.nonNull(emailBis) && StringUtils.isNotEmpty(emailBis.getEmail())) {
                sendEmailToSupplier("JW_POST_159", emailBis.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
            if (Objects.nonNull(emailFin) && StringUtils.isNotEmpty(emailFin.getEmail())) {
                sendEmailToSupplier("JW_POST_159", emailFin.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
            //增加业务经理
            if (Objects.nonNull(emailJl) && StringUtils.isNotEmpty(emailJl.getEmail())) {
                sendEmailToSupplier("JW_POST_159", emailJl.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
        }else {
            // 变更对账单相关数据
            head.setStatus(9);
            if ("1100".equals(head.getCompanyCode())){
                head.setStatus(9);
            }
            // 更新对账单主表信息
            if(!costAccountStatementService.updateById(head)){
                throw new DaoException("更新对账单主表数据失败, 请联系管理员");
            }
            //异步邮件通知 供应商 12业务接口人 4财务人员 2024-11-13 邓京术
            SupplierContactsDTO emailBis = supplierClient.getDefaultContact(head.getSupplierCode(), "12");
            SupplierContactsDTO emailFin = supplierClient.getDefaultContact(head.getSupplierCode(), "4");
            SupplierContactsDTO emailJl = supplierClient.getDefaultContact(head.getSupplierCode(), "5");

            if (Objects.nonNull(emailBis) && StringUtils.isNotEmpty(emailBis.getEmail())) {
                sendEmailToSupplier("JW_POST_113", emailBis.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
            if (Objects.nonNull(emailFin) && StringUtils.isNotEmpty(emailFin.getEmail())) {
                sendEmailToSupplier("JW_POST_113", emailFin.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
            //增加业务经理
            if (Objects.nonNull(emailJl) && StringUtils.isNotEmpty(emailJl.getEmail())) {
                sendEmailToSupplier("JW_POST_113", emailJl.getEmail(), head.getSupplierName(), head.getAccountStatementNo(),param.getApproveOpinion());
            }
        }

        // 2.记录原因
        CostAccountStatementApprove approve = new CostAccountStatementApprove();
        approve.setAsId(head.getId());
        approve.setAsNo(head.getAccountStatementNo());
        approve.setApproveResult(param.getApproveStatus());
        approve.setApproveOpinion(param.getApproveOpinion());
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 财务节点
        approve.setApproveNode(2);
        approve.setApproveTime(LocalDateTime.now());
        costAccountStatementApproveService.save(approve);
    }

    @Override
    public void revokeFinConfirmed(Long asId, String revokeReason) {
        final CostAccountStatement statement = costAccountStatementService.getById(asId);
        if(null == statement){
            throw new DaoException("系统未找到相应的对账单信息");
        }
        if(9 != statement.getStatus()){
            throw new DaoException("对账单不能进行撤销操作, 请检查对账单状态");
        }

        CostInvoicedApply invoicedApply = costInvoicedApplyService.getOne(Wrappers.lambdaQuery(CostInvoicedApply.class).eq(CostInvoicedApply::getAccountStatementId,statement.getId()).eq(CostInvoicedApply::getDeleteFlag,0).last(" limit 1"));
        if (ObjectUtil.isNotNull(invoicedApply)){
            throw new DaoException("对账单: " + statement.getAccountStatementNo() + "不能被撤销，已被开票申请："+invoicedApply.getInvoiceApplyNo()+"使用");
        }

        // 1.撤销时对账单状态由7(待财务确认)变更为2(待采购确认)
        CostAccountStatement updateHead = new CostAccountStatement();
        updateHead.setId(statement.getId());
        updateHead.setStatus(7);
        updateHead.setUpdateUserId(LoginUtil.getUserId());
        updateHead.setUpdateUserCode(LoginUtil.getAccount());
        updateHead.setUpdateUserName(LoginUtil.getName());
        updateHead.setUpdateTime(LocalDateTime.now());
        costAccountStatementService.updateById(updateHead);

        // 2.记录撤销原因
        CostAccountStatementApprove approve = new CostAccountStatementApprove();
        approve.setAsId(statement.getId());
        approve.setAsNo(statement.getAccountStatementNo());
        approve.setApproveResult(3);
        approve.setApproveOpinion(revokeReason);
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 撤销只能由采购操作
        approve.setApproveNode(2);
        approve.setApproveTime(LocalDateTime.now());
        costAccountStatementApproveService.save(approve);
        //
        //异步邮件通知 供应商 12业务接口人 4财务人员 2024-11-14 邓京术
        SupplierContactsDTO emailBis = supplierClient.getDefaultContact(statement.getSupplierCode(), "12");
        SupplierContactsDTO emailFin = supplierClient.getDefaultContact(statement.getSupplierCode(), "4");
        sendEmailToSupplier("JW_POST_114", emailBis.getEmail(), statement.getSupplierName(), statement.getAccountStatementNo(),"");
        sendEmailToSupplier("JW_POST_114", emailFin.getEmail(), statement.getSupplierName(), statement.getAccountStatementNo(),"");
    }

    /**
     * 更新对账单已开票标识
     *
     * @param asId                对账单ID
     * @param invoiceCompleteFlag
     */
    @Override
    public void updateInvoiceCompleteFlagByAsId(Long asId, int invoiceCompleteFlag) {
        CostAccountStatement as = new CostAccountStatement();
        as.setInvoiceCompleteFlag(invoiceCompleteFlag);
        as.setId(asId);
        costAccountStatementService.updateById(as);
    }

    @Override
    public List<CostAccountStatementDTO> accountOrApplyList(CostAccountStatementQuery query) {
        List<PaymentStatementFilterConfig> statementFilterlist = paymentStatementFilterConfigService.list(Wrappers.lambdaQuery(PaymentStatementFilterConfig.class).eq(PaymentStatementFilterConfig::getDeleteFlag,0));
        List<CostAccountStatementPO> accountStatementPOS = costAccountStatementService.accountOrApplyList(null, query);
        List<CostAccountStatementDTO> accountStatementDTOS = costAccountStatementConvert.po2PageListDTO(accountStatementPOS);
        accountStatementDTOS.forEach(accountStatementDTO -> {
            accountStatementDTO.setAlreadyApplyAmount(BigDecimal.ZERO);
            accountStatementDTO.setAlreadyPaymentAmount(BigDecimal.ZERO);
            accountStatementDTO.setStrikePriceAmount(accountStatementDTO.getStrikePriceAmount()==null?BigDecimal.ZERO:accountStatementDTO.getStrikePriceAmount());
            accountStatementDTO.setActualUnpaidAmount(accountStatementDTO.getActualUnpaidAmount()==null?accountStatementDTO.getTaxAmount():accountStatementDTO.getActualUnpaidAmount());
        });
        List<CostAccountStatementDTO> paymentAdvanceApplyList= Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(accountStatementDTOS)){
            //根据已获取的过账数据筛选已经货到付款的数据
            List<CreatePcaDetailPO> alreadyData = paymentCodApplyDetailService.findByCostAccountCodeAndItem(accountStatementPOS);
            //处理数据开票数据
            for(CostAccountStatementDTO detailDto:accountStatementDTOS){
                for(CreatePcaDetailPO dto:alreadyData){
                    if(detailDto.getAccountStatementNo().equals(dto.getDataKey())){
                        //已申请金额
                        detailDto.setAlreadyApplyAmount(detailDto.getAlreadyApplyAmount().add(dto.getBudInnerMoney()).add(dto.getBudOutMoney()));
                        //已付款金额
                        if(dto.getStatus() == 5){
                            detailDto.setAlreadyPaymentAmount(detailDto.getAlreadyPaymentAmount().add(dto.getBudInnerMoney()).add(dto.getBudOutMoney()));
                        }
                        break;
                    }
                }
                detailDto.setApplyAmount(detailDto.getActualUnpaidAmount().subtract(detailDto.getAlreadyApplyAmount() == null? BigDecimal.ZERO:detailDto.getAlreadyApplyAmount()));
                //如果可申请付款金额不为0，可以继续付款
                if (detailDto.getApplyAmount().compareTo(BigDecimal.ZERO)!=0){
                    paymentAdvanceApplyList.add(detailDto);
                }
            }
        }

        //2025-02-04新增对账单付款查询过滤逻辑
        if(CollectionUtils.isNotEmpty(statementFilterlist) && CollectionUtils.isNotEmpty(paymentAdvanceApplyList)) {
            //存在过滤的对账单则删除不返回
            Set<String> StatementNoSet = statementFilterlist.stream()
                    .map(PaymentStatementFilterConfig::getAccountStatementNo)
                    .collect(Collectors.toSet());
            Iterator<CostAccountStatementDTO> iterator = paymentAdvanceApplyList.iterator();
            while (iterator.hasNext()) {
                CostAccountStatementDTO entity = iterator.next();
                if (StatementNoSet.contains(entity.getAccountStatementNo())) {
                    iterator.remove();
                }
            }
        }
        return paymentAdvanceApplyList;
    }

    private void sendEmailToSupplier(String templeteCode, String receiver, String supplierName, String accountStatementCode, String reason) {
        try {
            final EmailTmpSingleSendDTO emailTxtSingleSendDTO = new EmailTmpSingleSendDTO();
            emailTxtSingleSendDTO.setTemplateCode(templeteCode);
            Map<String, Object> params = Maps.newHashMap();
            params.put("url", sysProp.getWebsiteUrl());
            params.put("supplierName", supplierName);
            params.put("accountCode", accountStatementCode);
            params.put("reason", reason);
            params.put("date",DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            emailTxtSingleSendDTO.setParams(params);
            emailTxtSingleSendDTO.setReceiver(receiver);
            emailTxtSingleSendDTO.setSender(LoginUtil.getUserId());
            emailSendClient.async(emailTxtSingleSendDTO);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//    private void initMaterialName(StatementItemPO po , Map<String,String> materialNameMap) {
//        if (materialNameMap.keySet().contains(po.getMaterialCode())) {
//            po.setMaterialName(materialNameMap.get(po.getMaterialCode()));
//        } else {
//            ProductInfoDTO productInfoDTO = productClient.getByMaterialCodeAndFactoryCode(po.getMaterialCode());
//            if (Objects.nonNull(productInfoDTO)) {
//                materialNameMap.put(po.getMaterialCode(), productInfoDTO.getMaterialDesc());
//                po.setMaterialName(productInfoDTO.getMaterialDesc());
//            }
//        }
//    }
}
