package com.jwipc.finance.logic.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.SapResposeBody;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.constant.AccountStatementSapClient;
import com.jwipc.finance.convert.CostMatchingConvert;
import com.jwipc.finance.convert.CostMatchingPaymentNoticeRelationConvert;
import com.jwipc.finance.convert.CostMatchingReceiveVoucherRelationConvert;
import com.jwipc.finance.dto.*;
import com.jwipc.finance.entity.*;
import com.jwipc.finance.logic.CostMatchingLogic;
import com.jwipc.finance.logic.ReceiptVoucherLogic;
import com.jwipc.finance.model.po.CostMatchingPO;
import com.jwipc.finance.model.po.CustomsDeclarationDetailPO;
import com.jwipc.finance.model.po.PaymentNoticeDetailPO;
import com.jwipc.finance.model.po.StatementItemPO;
import com.jwipc.finance.model.query.CostMatchingQuery;
import com.jwipc.finance.service.*;
import com.jwipc.order.client.PurchaseOrderClient;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.dto.BusinessAttachmentDTO;
import com.jwipc.sys.dto.DigitalSealBusinessDetailDTO;
import com.jwipc.sys.dto.KingdeeInvoiceCloudImageDTO;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.entity.DigitalSealBusinessDetail;
import com.jwipc.sys.logic.BusinessAttachmentLogic;
import com.jwipc.sys.logic.KingdeeImageLogic;
import com.jwipc.sys.service.IBusinessAttachmentService;
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.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;

/**
 * @author shenyang.ou
 * @date 2025/10/22 15:29
 * @desc
 */
@Service
@RequiredArgsConstructor
public class CostMatchingLogicImpl implements CostMatchingLogic {
    private final ICostMatchingService costMatchingService;
    private final ICostMatchingApproveService costMatchingApproveService;
    private final IPaymentNoticeDetailService paymentNoticeDetailService;
    private final IReceiveVoucherService receiveVoucherService;
    private final AccountStatementSapClient accountStatementSapClient;
    private final ICostMatchingPaymentNoticeRelationService costMatchingPaymentNoticeRelationService;
    private final ICostAccountStatementDetailService costAccountStatementDetailService;
    private final ICostMatchingReceiveVoucherRelationService costMatchingReceiveVoucherRelationService;
    private final CostMatchingConvert costMatchingConvert;
    private final CostMatchingPaymentNoticeRelationConvert costMatchingPaymentNoticeRelationConvert;
    private final ReceiptVoucherLogic receiptVoucherLogic;
    private final CostMatchingReceiveVoucherRelationConvert costMatchingReceiveVoucherRelationConvert;
    private final SequenceClient sequenceClient;
    private final DictClient dictClient;
    private final PurchaseOrderClient purchaseOrderClient;
    private final SupplierClient supplierClient;
    private final IBusinessAttachmentService businessAttachmentService;
    private final BusinessAttachmentLogic businessAttachmentLogic;
    private final KingdeeImageLogic kingdeeImageLogic;
    @Override
    public PageView findByPage(CostMatchingQuery query) {
        final Page<CostMatching> dbPage = PageUtil.toPage(query);
        List<CostMatchingPO> priceInfoAuditPOS = costMatchingService.findPageByQuery(dbPage, query);
        List<CostMatchingDTO> priceInfoAuditDTOS = costMatchingConvert.po2DTOList(priceInfoAuditPOS);

        //加载附件
        if (CollUtil.isNotEmpty(priceInfoAuditDTOS)){
            final Set<Long> ids = priceInfoAuditDTOS.stream().map(CostMatchingDTO::getId).collect(Collectors.toSet());
            final List<BusinessAttachment> businessAttachmentList = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>()
                    .in(BusinessAttachment::getBusinessId, ids).eq(BusinessAttachment::getBusinessTypeCode, "cost_matching"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (CostMatchingDTO dto : priceInfoAuditDTOS) {
                if (Objects.nonNull(businessAttachmentMap.get(dto.getId()))) {
                    dto.setAttachmentFiles("1");
                }
            }
        }
        return PageUtil.getPV(priceInfoAuditDTOS, dbPage.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public void saveOrUpdate(CostMatchingParamDTO param) {
        if (param.getId() == null) {
            param.setCode(sequenceClient.createSequenceNo("cost_matching_no"));
            param.setStatus(1);
            param.setCreateTime(LocalDateTime.now());
            param.setCreateUser(LoginUtil.getUserId());
        } else {
            param.setUpdateTime(LocalDateTime.now());
            param.setUpdateUser(LoginUtil.getUserId());
            //删除明细
            costMatchingPaymentNoticeRelationService.remove(Wrappers.lambdaQuery(CostMatchingPaymentNoticeRelation.class).eq(CostMatchingPaymentNoticeRelation::getMainId,param.getId()));
            costMatchingReceiveVoucherRelationService.remove(Wrappers.lambdaQuery(CostMatchingReceiveVoucherRelation.class).eq(CostMatchingReceiveVoucherRelation::getMainId,param.getId()));
        }
        if (StrUtil.isEmpty(param.getRemark())&& StrUtil.isNotEmpty(param.getPaymentNoticeDetailCode())){
            param.setRemark(param.getPaymentNoticeDetailCode()+"_运杂费_增值税_关税");
        }
        //保存主数据
        CostMatching priceInfoAudit = costMatchingConvert.DTO2Entity(param);
        costMatchingService.saveOrUpdate(priceInfoAudit);
        final List<CostMatchingPaymentNoticeRelationDTO> customsDeclarationRelationList = param.getPaymentNoticeRelationList();
        AtomicInteger index = new AtomicInteger(1);
        customsDeclarationRelationList.forEach(priceInfoAuditDetailDTO -> {
            priceInfoAuditDetailDTO.setId(null);
            priceInfoAuditDetailDTO.setMainCode(priceInfoAudit.getCode());
            priceInfoAuditDetailDTO.setMainId(priceInfoAudit.getId());
            priceInfoAuditDetailDTO.setCustomsType(param.getCustomsType());
            index.getAndIncrement();
        });
        costMatchingPaymentNoticeRelationService.saveBatch(costMatchingPaymentNoticeRelationConvert.dto2EntityList(customsDeclarationRelationList));

        final List<CostMatchingReceiveVoucherRelationDTO> receiveVoucherRelationList = param.getReceiveVoucherRelationList();
        // 校验对账单明细的出入库明细数据
        List<Long> rvIdList = Lists.newArrayList();
        for(CostMatchingReceiveVoucherRelationDTO asd: receiveVoucherRelationList){
            rvIdList.add(asd.getReceiveVoucherId());
        }
        final String checkResult = receiptVoucherLogic.checkConsultVoucher(rvIdList,param.getSupplierCode(), null);
        if(StringUtils.isNotEmpty(checkResult)){
            throw new DaoException(checkResult);
        }
        AtomicInteger index1 = new AtomicInteger(1);
        receiveVoucherRelationList.forEach(priceInfoAuditDetailDTO -> {
            priceInfoAuditDetailDTO.setId(null);
            priceInfoAuditDetailDTO.setMainCode(priceInfoAudit.getCode());
            priceInfoAuditDetailDTO.setMainId(priceInfoAudit.getId());
            priceInfoAuditDetailDTO.setCustomsType(param.getCustomsType());
            index1.getAndIncrement();
        });
        costMatchingReceiveVoucherRelationService.saveBatch(costMatchingReceiveVoucherRelationConvert.dto2EntityList(receiveVoucherRelationList));

        // 附件关系
//        businessAttachmentService.remove(Wrappers.lambdaQuery(BusinessAttachment.class).eq(BusinessAttachment::getBusinessId, priceInfoAudit.getId()));
//        List<BusinessAttachmentDTO> businessAttachmentDTOList = param.getBusinessAttachmentDTOList();
//        businessAttachmentDTOList.forEach(item -> {
//            item.setId(null);
//            item.setBusinessId(priceInfoAudit.getId());
//            item.setBusinessTypeCode("cost_matching");
//        });
//        businessAttachmentLogic.saveAttachment(businessAttachmentDTOList);
//
//
//        //影像化
//        this.toImg(priceInfoAudit.getId());
    }

    /**
     * 影像化
     *
     * @param id ID
     */
    @Override
    public void toImg(Long id) {
        CostMatching invoicedApply = costMatchingService.getById(id);
        //影像化
        List<BusinessAttachmentDTO> accountStatementAttachments = businessAttachmentLogic.getListByBusinessId(id);
        if (CollUtil.isNotEmpty(accountStatementAttachments)) {
            KingdeeInvoiceCloudImageDTO kingdeeInvoiceCloudImageDTO = new KingdeeInvoiceCloudImageDTO();
            kingdeeInvoiceCloudImageDTO.setImageCode(StrUtil.isNotEmpty(invoicedApply.getImgCode()) ? invoicedApply.getImgCode() : sequenceClient.createSequenceNo("image_code"));
            if (CollUtil.isNotEmpty(accountStatementAttachments)) {
                kingdeeInvoiceCloudImageDTO.setBusinessAttachmentList(accountStatementAttachments);
                KingdeeInvoiceCloudImageDTO result = kingdeeImageLogic.pushImage(kingdeeInvoiceCloudImageDTO);
                costMatchingService.update(new LambdaUpdateWrapper<CostMatching>().set(CostMatching::getImgCode, result.getImageCode()).set(CostMatching::getImgTime, LocalDateTime.now()).set(CostMatching::getImgUserId, LoginUtil.getUserId())
                        .eq(CostMatching::getId, id));
            }

        }
    }

    /**
     * 删除影像化
     *
     * @param id ID
     */
    @Override
    public void deleteImg(Long id) {
        //删除影像化
//        CostMatching invoicedApply = costMatchingService.getById(id);
        CostMatching accountStatement = costMatchingService.getById(id);
        if (ObjectUtil.isNull(accountStatement.getImgTime())){
            return;
        }
        List<BusinessAttachment> businessAttachments = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>().eq(BusinessAttachment::getBusinessId, id));
        if (CollUtil.isNotEmpty(businessAttachments)) {
            //过滤出accountStatementAttachments中存在imageCode的数据
            List<BusinessAttachment> accountStatementAttachmentsImageCode = businessAttachments.stream().filter(accountStatementAttachment -> StringUtils.isNotEmpty(accountStatementAttachment.getImageCode())).toList();
            if (CollUtil.isNotEmpty(accountStatementAttachmentsImageCode)) {
                KingdeeInvoiceCloudImageDTO kingdeeInvoiceCloudImageDTO = new KingdeeInvoiceCloudImageDTO();
                kingdeeInvoiceCloudImageDTO.setImageCode(accountStatementAttachmentsImageCode.get(0).getImageCode());
                kingdeeImageLogic.deleteAllImage(kingdeeInvoiceCloudImageDTO);
                costMatchingService.update(new LambdaUpdateWrapper<CostMatching>()
//                        .set(InvoicedApply::getImgCode,null)
                        .set(CostMatching::getImgTime, null)
                        .set(CostMatching::getImgUserId, null)
                        .eq(CostMatching::getId, id));
            }
        }
    }

    @Override
    @Transactional
    public void remove(Long id) {
        costMatchingService.update(Wrappers.lambdaUpdate(CostMatching.class).set(CostMatching::getDeleteFlag,1).eq(CostMatching::getId,id));
        List<CostMatchingPaymentNoticeRelation> costMatchingPaymentNoticeRelations = costMatchingPaymentNoticeRelationService.list(Wrappers.lambdaQuery(CostMatchingPaymentNoticeRelation.class).eq(CostMatchingPaymentNoticeRelation::getMainId,id));
        if (CollUtil.isNotEmpty(costMatchingPaymentNoticeRelations)){
            for (CostMatchingPaymentNoticeRelation costMatchingPaymentNoticeRelation : costMatchingPaymentNoticeRelations){
                CostAccountStatementDetail costAccountStatementDetail = costAccountStatementDetailService.getOne(new LambdaQueryWrapper<>(CostAccountStatementDetail.class)
                        .eq(CostAccountStatementDetail::getCostMatchingPaymentNoticeRelationId,costMatchingPaymentNoticeRelation.getId())
                        .eq(CostAccountStatementDetail::getDeleteFlag,0).last(" limit 1"));
                if (ObjectUtil.isNotNull(costAccountStatementDetail)){
                    throw new DaoException("费用匹配明细已被费用对账单使用不可删除，费用对账单号："+costAccountStatementDetail.getAsNo());
                }
            }
        }
        //删除明细
        costMatchingPaymentNoticeRelationService.update(Wrappers.lambdaUpdate(CostMatchingPaymentNoticeRelation.class).set(CostMatchingPaymentNoticeRelation::getDeleteFlag,1).eq(CostMatchingPaymentNoticeRelation::getMainId,id));
        costMatchingReceiveVoucherRelationService.update(Wrappers.lambdaUpdate(CostMatchingReceiveVoucherRelation.class).set(CostMatchingReceiveVoucherRelation::getDeleteFlag,1).eq(CostMatchingReceiveVoucherRelation::getMainId,id));
    }

    @Override
    @Transactional
    public void pushConfirm(Long id) {
        CostMatching costMatching = costMatchingService.getById(id);
        costMatching.setStatus(7);
        costMatching.setUpdateTime(LocalDateTime.now());
        costMatching.setUpdateUser(LoginUtil.getUserId());
        costMatchingService.updateById(costMatching);
    }

    @Override
    @Transactional
    public CostMatchingDTO getById(Long id) {
        CostMatching costMatching = costMatchingService.getById(id);
        return costMatchingConvert.entity2DTO(costMatching);
    }


    @Override
    @Transactional
    public void financeConfirm(CostMatchingParamDTO param) {
        CostMatching costMatching = costMatchingService.getById(param.getId());
        costMatching.setStatus(param.getApproveStatus()==1?9:8);
        costMatching.setFinanceConfirmTime(LocalDateTime.now());
        costMatching.setFinanceConfirmUser(LoginUtil.getUserId());
        costMatchingService.updateById(costMatching);
        // 2.记录原因
        CostMatchingApprove approve = new CostMatchingApprove();
        approve.setMainId(costMatching.getId());
        approve.setMainNo(costMatching.getCode());
        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());
        costMatchingApproveService.save(approve);
    }

    /**
     * 匹配单删除
     *
     * @param ids         ID
     * @param logicDelete 是否逻辑删除
     */
    @Override
    public void dataDel(String ids, Boolean logicDelete) {
        if (StringUtils.isEmpty(ids)) {
            throw new DaoException("参数异常, 请重新操作");
        }
        final List<Long> idList = JSONArray.parseArray(ids, Long.class);
        final List<CostMatching> list = costMatchingService.list(new LambdaQueryWrapper<CostMatching>().in(CostMatching::getId, idList));
        for (CostMatching costMatching : list) {
            costMatching.setDeleteFlag(1);
            costMatching.setUpdateUser(StpUtil.isLogin()?LoginUtil.getUserId():1L);
            costMatching.setUpdateTime(LocalDateTime.now());
            costMatchingService.updateById(costMatching);
        }

        List<CostMatchingPaymentNoticeRelation> updateIadList = costMatchingPaymentNoticeRelationService.list(new LambdaQueryWrapper<CostMatchingPaymentNoticeRelation>().in(CostMatchingPaymentNoticeRelation::getMainId, idList));
        for (CostMatchingPaymentNoticeRelation paymentNoticeRelation : updateIadList) {
            paymentNoticeRelation.setDeleteFlag(1);
            paymentNoticeRelation.setUpdateUser(StpUtil.isLogin()?LoginUtil.getUserId():1L);
            paymentNoticeRelation.setUpdateTime(LocalDateTime.now());
            costMatchingPaymentNoticeRelationService.updateById(paymentNoticeRelation);
        }

        List<CostMatchingReceiveVoucherRelation> receiveVoucherRelations = costMatchingReceiveVoucherRelationService.list(new LambdaQueryWrapper<CostMatchingReceiveVoucherRelation>().in(CostMatchingReceiveVoucherRelation::getMainId, idList));
        for (CostMatchingReceiveVoucherRelation costMatchingReceiveVoucherRelation : receiveVoucherRelations) {
            costMatchingReceiveVoucherRelation.setDeleteFlag(1);
            costMatchingReceiveVoucherRelation.setUpdateUser(StpUtil.isLogin()?LoginUtil.getUserId():1L);
            costMatchingReceiveVoucherRelation.setUpdateTime(LocalDateTime.now());
            costMatchingReceiveVoucherRelationService.updateById(costMatchingReceiveVoucherRelation);
        }
    }

    @Override
    public void createPrefabricateInvoice(Long id, Integer type, String invoicePostDate, String statementType) {
        CostMatching costMatching = costMatchingService.getById(id);
        //过账状态 1:暂存 2:待预制 3:预制失败 7:已冲销 2024-08-21 邓京术 财务要求 3和7的也允许过账
        if (ObjectUtil.isNotEmpty(costMatching)){
            if (costMatching.getPostStatus() != 1&&costMatching.getPostStatus() != 2&&costMatching.getPostStatus() != 3&&costMatching.getPostStatus() != 7){
                throw new DaoException(StrUtil.format("费用匹配单:{}已过账，不允许再次过账",costMatching.getCode()));
            }
        }
//        List<PaymentNoticeDetailPO> list = paymentNoticeDetailService.provideDetailByCostMatchingId(id);
        List<StatementItemPO> statementItemPOS = receiveVoucherService.provideDetailByCostMatchingId(id);
        statementItemPOS.forEach(dto -> {
            if (dto.getVoucherFlag().equals("H")){
                if (dto.getTaxAmount().compareTo(BigDecimal.ZERO) > 0) { // 只有正数才取负
                    dto.setTaxAmount(dto.getTaxAmount().negate());
                    dto.setMvNum(dto.getMvNum().negate());
                }
            }
        });
        //组装数据传入对账数据到sap接口
        final PaymentToSapDTO accountStatementToSapDTO = new PaymentToSapDTO();
        //头
        final PaymentToSapDTO.ItHead itHead = new PaymentToSapDTO.ItHead();
        itHead.item = Lists.newArrayList();
        PaymentToSapDTO.Head head = new PaymentToSapDTO.Head();
        //SRM单号
        head.setZSRMBILLNO(costMatching.getCode());
        // 业务类型
        head.setYWLX("02");
        // 法人主体
        head.setBUKRS(costMatching.getCompanyCode());
        // 发票日期
        head.setBLDAT(LocalDateTimeUtil.format(costMatching.getInvoiceDate(),"yyyyMMdd"));
        // 过账日期
        head.setBUDAT(LocalDateTimeUtil.format(LocalDateTimeUtil.parse(invoicePostDate,"yyyy-MM-dd"),"yyyyMMdd"));
        // 币别
        head.setWAERS(costMatching.getCurrencyCode());
        // 金额（RMWWR）
        head.setRMWWR(costMatching.getCustomsPaymentCertificateTaxAmount().add(costMatching.getSharedExpenseAmount()).stripTrailingZeros().toPlainString());
        // 税额
        head.setWMWST1("0");
        // 文本
        head.setSGTXT(costMatching.getRemark());
        // 供应商
        head.setLIFNR(costMatching.getSupplierCode());
        // 总账科目
        head.setHKONT("");
        // 借/贷
        head.setSHKZG("");
        // 金额（WRBTR）
        head.setWRBTR(costMatching.getCustomsPaymentCertificateTaxAmount().stripTrailingZeros().toPlainString());
        itHead.item.add(head);
        //明细
        final PaymentToSapDTO.ItItem itItem = new PaymentToSapDTO.ItItem();
        itItem.item = Lists.newArrayList();
        for(StatementItemPO dto: statementItemPOS){
            PaymentToSapDTO.Item item = new PaymentToSapDTO.Item();
            // 采购订单
            item.setEBELN(dto.getPoCode());
            // 项目（采购订单行项目）
            item.setEBELP(dto.getPoItemNo());
            // 金额
            item.setWRBTR(dto.getSharedAmount().stripTrailingZeros().toPlainString());
            // 数量
            item.setMENGE(dto.getMvNum().stripTrailingZeros().toPlainString());
            // 物料凭证
            item.setMBLNR(dto.getMvCode());
            // 项目（物料凭证行项目）
            item.setZEILE(dto.getReceiveRowNo());
            // 年度
            item.setMJAHR(dto.getReceiveYear());
            itItem.item.add(item);
        }
        accountStatementToSapDTO.setIT_HEAD(itHead);
        accountStatementToSapDTO.setIT_ITEM(itItem);

        SapResposeBody sapResposeBody = accountStatementSapClient.syncPayment(accountStatementToSapDTO);
        if (sapResposeBody.getES_RET().getCODE().equals(RestCode.SAP_SUCCESS.getCode())) {
            costMatching.setPostStatus(4);
            costMatching.setPostMsg("成功");
            costMatching.setPostDate(LocalDateTimeUtil.parseDate(invoicePostDate,"yyyy-MM-dd"));
            costMatching.setPostOptTime(LocalDateTime.now());
            costMatching.setPostUser(LoginUtil.getUserId());
            costMatchingService.updateById(costMatching);
        }else {
            costMatching.setPostStatus(3);
            costMatching.setPostMsg(sapResposeBody.getES_RET().getMSG());
            costMatching.setPostDate(LocalDateTimeUtil.parseDate(invoicePostDate,"yyyy-MM-dd"));
            costMatching.setPostOptTime(LocalDateTime.now());
            costMatching.setPostUser(LoginUtil.getUserId());
            costMatchingService.updateById(costMatching);
            throw new DaoException("SAP接口报错：" + sapResposeBody.getES_RET().getMSG());
        }
    }
}
