package com.sunxung.factoring.service.refundsManagement.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunxung.factoring.component.exception.BusinessException;
import com.sunxung.factoring.component.exception.ValidatorException;
import com.sunxung.factoring.component.util.CodeUtil;
import com.sunxung.factoring.component.util.CollectionUtil;
import com.sunxung.factoring.component.util.ConstantConversionUtil;
import com.sunxung.factoring.component.util.ConstantUtil;
import com.sunxung.factoring.dict.impl.*;
import com.sunxung.factoring.entity.ResponseJson;
import com.sunxung.factoring.entity.cashflowmanage.CashFlowManageBasicInfo;
import com.sunxung.factoring.entity.cashflowmanage.CashFlowManageOutInfo;
import com.sunxung.factoring.entity.cashflowmanage.request.AddCashFlowRequest;
import com.sunxung.factoring.entity.cashflowmanage.sop.BankAccountInfo;
import com.sunxung.factoring.entity.cashflowmanage.sop.BillingNonbusinessManageFactoringentry;
import com.sunxung.factoring.entity.customerinformation.SupplierBankCardInfo;
import com.sunxung.factoring.entity.entprise.Enterprise;
import com.sunxung.factoring.entity.ledger.CashFlowManageBasicPayCollPlanRef;
import com.sunxung.factoring.entity.ledger.LedgerAccountBasicInfo;
import com.sunxung.factoring.entity.ledger.LedgerFundGoodsAssign;
import com.sunxung.factoring.entity.project.ProjectInformation;
import com.sunxung.factoring.entity.refundsManagement.*;
import com.sunxung.factoring.entity.supplier.SupplierInfo;
import com.sunxung.factoring.entity.sys.Dictionary;
import com.sunxung.factoring.entity.sys.User;
import com.sunxung.factoring.entity.tradingPlatform.Platform;
import com.sunxung.factoring.mapper.refundsManagement.RefundManagementApprovalMapper;
import com.sunxung.factoring.service.cashflowmanage.CashFlowManageBasicInfoService;
import com.sunxung.factoring.service.cashflowmanage.CashFlowManageOutInfoService;
import com.sunxung.factoring.service.customerinformation.SupplierBankCardInfoService;
import com.sunxung.factoring.service.entprise.IEnterpriseService;
import com.sunxung.factoring.service.ledger.ICashFlowManageBasicPayCollPlanRefService;
import com.sunxung.factoring.service.ledger.LedgerAccountBasicInfoService;
import com.sunxung.factoring.service.ledger.LedgerFundGoodsAssignService;
import com.sunxung.factoring.service.project.BusinessProcessingLogService;
import com.sunxung.factoring.service.project.IProjectInformationService;
import com.sunxung.factoring.service.refundsManagement.*;
import com.sunxung.factoring.service.supplier.ISupplierInfoService;
import com.sunxung.factoring.service.sys.DictionaryService;
import com.sunxung.factoring.service.sys.UserService;
import com.sunxung.factoring.service.sys.flowable.FlowableService;
import com.sunxung.factoring.service.tradingPlatform.PlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 退款管理审批表 服务实现类
 * </p>
 *
 * @author yafan
 * @since 2024-03-11
 */
@Service("refund_approvalService")
public class RefundManagementApprovalServiceImpl extends ServiceImpl<RefundManagementApprovalMapper,
        RefundManagementApproval> implements IRefundManagementApprovalService {

    @Autowired
    private IRefundDetailsService refundDetailsService;
    @Autowired
    private IRefundsApplyDetailsService refundsApplyDetailsService;
    @Autowired
    private IRefundsApplyAccountInfoService refundsApplyAccountInfoService;
    @Autowired
    private IRefundManagementPayCollPlanFactoringRefService refundManagementPayCollPlanFactoringRefService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IRefundManagementService refundManagementService;
    @Autowired
    private FlowableService flowableService;
    @Autowired
    private BusinessProcessingLogService businessProcessingLogService;
    @Value("${sop.applyOtherOAUrl}")
    private String applyOtherOAUrl;
    @Autowired
    private IRefundsApplyDetailsPayCollPlanRefService refundsApplyDetailsPayCollPlanRefService;
    @Autowired
    private IRefundDetailsRefundsApplyDetailsRefService refundDetailsRefundsApplyDetailsRefService;
    @Autowired
    private CashFlowManageOutInfoService cashFlowManageOutInfoService;
    @Autowired
    private CashFlowManageBasicInfoService cashFlowManageBasicInfoService;
    @Autowired
    private PlatformService platformService;
    @Autowired
    @Resource(name = "projectInformationService")
    private IProjectInformationService projectInformationService;
    @Autowired
    private ISupplierInfoService supplierInfoService;
    @Autowired
    private IEnterpriseService enterpriseService;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private UserService userService;
    @Autowired
    private IRefundManagementApprovalApplyDetailsRefService refundManagementApprovalApplyDetailsRefService;
    @Autowired
    private ICashFlowManageBasicPayCollPlanRefService cashFlowManageBasicPayCollPlanRefService;
    @Autowired
    private LedgerAccountBasicInfoService ledgerAccountBasicInfoService;
    @Autowired
    private SupplierBankCardInfoService supplierBankCardInfoService;
    @Autowired
    private LedgerFundGoodsAssignService ledgerFundGoodsAssignService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doEdit(RefundManagementApproval approval) {


        save(approval);
        if (ConstantConversionUtil.APPROVAL_RESULT_PASS.equals(approval.getApprovalConclusion())) {

            RefundManagement refundManagement = refundManagementService
                    .lambdaQuery().eq(RefundManagement::getId, approval.getRefundManagementId()).one();

            List<RefundsApplyDetails> applyDetailsList = refundsApplyDetailsService.lambdaQuery()
                    .eq(RefundsApplyDetails::getRefundManagementId, approval.getRefundManagementId())
                    .eq(RefundsApplyDetails::getStatus, 0).list();

            if (CollectionUtil.isNotEmpty(applyDetailsList)) {
                for (RefundsApplyDetails apply : applyDetailsList) {
                    if (1 == apply.getApplyType()) {

                        //填充银行账户信息
                        ProjectInformation projectInformation = projectInformationService
                                .lambdaQuery().eq(ProjectInformation::getBusinessNumber, refundManagement.getBusinessNumber()).one();
                        SupplierInfo supplierInfo = supplierInfoService.get(projectInformation.getcSupplierInfoId());
                        Enterprise supplier = enterpriseService.getById(supplierInfo.getcEnterpriseId());
                        List<LedgerFundGoodsAssign> fundGoodsAssignList = ledgerFundGoodsAssignService
                                .lambdaQuery().eq(LedgerFundGoodsAssign::getBusinessNumber, refundManagement.getBusinessNumber())
                                .list();
                        if (CollectionUtil.isNotEmpty(fundGoodsAssignList)) {
                            List<LedgerAccountBasicInfo> ledgerAccountBasicInfos = fundGoodsAssignList.stream().map(fundGoodsAssign -> {
                                return ledgerAccountBasicInfoService.getById(fundGoodsAssign.getLedgerAccountBasicInfoId());
                            }).sorted(Comparator.comparing(LedgerAccountBasicInfo::getGmtCreate).reversed()).collect(Collectors.toList());
                            List<RefundsApplyAccountInfo> accountInfoList = new ArrayList<>();
                            if (CollectionUtil.isNotEmpty(ledgerAccountBasicInfos)) {
                                LedgerAccountBasicInfo accountBasicInfo = ledgerAccountBasicInfos.get(0);
                                SupplierBankCardInfo supplierBankCardInfo = supplierBankCardInfoService
                                        .lambdaQuery().eq(SupplierBankCardInfo::getLedgerAccountBasicInfoId, accountBasicInfo.getId())
                                        .eq(SupplierBankCardInfo::getSupplierId, supplier.getId())
                                        .one();
                                if (supplierBankCardInfo != null) {
                                    RefundsApplyAccountInfo applyAccountInfo = new RefundsApplyAccountInfo();
                                    applyAccountInfo.setCollectionAccount(supplierBankCardInfo.getAccountNumber());
                                    applyAccountInfo.setCollectionAccountName(supplierBankCardInfo.getAccountName());
                                    applyAccountInfo.setCollectionBankName(supplierBankCardInfo.getBankName());
                                    accountInfoList.add(applyAccountInfo);
                                }
                            }
                            apply.setAccountInfoList(accountInfoList);
                        }

                        //申请人
                        User user = userService.get(apply.getUserId());
                        apply.setUserName(user.getName());

                        //关联的计划
                        List<RefundManagementPayCollPlanFactoringRef> payCollPlanFactoringRefs = refundManagementPayCollPlanFactoringRefService
                                .lambdaQuery().eq(RefundManagementPayCollPlanFactoringRef::getRefundManagementId, approval.getId())
                                .eq(RefundManagementPayCollPlanFactoringRef::getStatus, 0)
                                .list();
                        if (CollectionUtil.isNotEmpty(payCollPlanFactoringRefs)) {
                            List<Long> planIds = payCollPlanFactoringRefs.stream()
                                    .map(RefundManagementPayCollPlanFactoringRef::getPayCollPlanFactoringId).collect(Collectors.toList());
                            apply.setPlanIds(planIds);
                        }

                        ResponseEntity<ResponseJson> responseEntity = null;
                        try {
                            responseEntity = restTemplate.postForEntity(applyOtherOAUrl, apply, ResponseJson.class);
                        } catch (Exception e) {
                            throw new BusinessException(CodeUtil.FAIL, "向sop推送OA申请报错啦，" + e.getMessage());
                        }

                        if (!responseEntity.getBody().getCode().equals("200")) {
                            throw new BusinessException(CodeUtil.FAIL, responseEntity.getBody().getMsg().toString());
                        }
                        refundManagement.setStage("OA审批");
                        refundManagementService.updateById(refundManagement);

                    } else {

                        //抵扣时新增入账信息
                        AddCashFlowRequest cashFlowRequest = new AddCashFlowRequest();
                        ProjectInformation projectInformation = projectInformationService
                                .lambdaQuery().eq(ProjectInformation::getBusinessNumber, refundManagement.getBusinessNumber())
                                .one();
                        if (projectInformation != null) {
                            SupplierInfo supplierInfo = supplierInfoService.get(projectInformation.getcSupplierInfoId());
                            Enterprise enterprise = enterpriseService.getById(supplierInfo.getcEnterpriseId());
                            cashFlowRequest.setCompanyId(enterprise.getId());
                        }
                        //默认非长银系
                        Dictionary noLongSilverDic = dictionaryService.getByCode(AttributionOfAccountDict.ChildEnum.NO_LONG_SILVER.getCode());
                        if (noLongSilverDic != null) {
                            cashFlowRequest.setAccountBelong(noLongSilverDic.getId());
                        }
                        Platform platform = platformService.getById(refundManagement.getTradingPlatformId());
                        Dictionary companyBelongDic = dictionaryService.getByNameAndParentCode(platform.getPlatformName(), CompanyOwnershipDict.CODE);
                        cashFlowRequest.setCompanyBelong(companyBelongDic.getId());
                        cashFlowRequest.setType(CashFlowEntryTypeDict.ChildEnum.CASH.getCode());
                        cashFlowRequest.setIncomeDate(apply.getPaymentDate());
                        cashFlowRequest.setIncomeAmount(apply.getPaymentAmountTotal());
                        cashFlowRequest.setRealAmount(apply.getPaymentAmountTotal());
                        autoBankInfo(cashFlowRequest, refundManagement.getTradingPlatformId());
                        //向现金流推送数据
                        cashFlowManageBasicInfoService.add(cashFlowRequest);
                        //闭合分账推送给现金流的数据
                        cashFlowComplete(apply, null);
                    }

                    RefundManagementApprovalApplyDetailsRef approvalApplyDetailsRef = new RefundManagementApprovalApplyDetailsRef();
                    approvalApplyDetailsRef.setRefundManagementApprovalId(approval.getId());
                    approvalApplyDetailsRef.setRefundsApplyDetailsId(apply.getId());
                    refundManagementApprovalApplyDetailsRefService.save(approvalApplyDetailsRef);
                }
            }
        }

        //更新相关状态
        updateStatus(approval);
        //处理流程
        handleProcess(approval);
    }

    @Override
    public RefundManagementApproval getView(Long id) {
        return getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleApprovalProcess(Long id) {

        List<RefundsApplyDetails> applyDetails = refundsApplyDetailsService.lambdaQuery().eq(RefundsApplyDetails::getRefundManagementId, id).list();
        if (CollectionUtil.isNotEmpty(applyDetails)) {
            //设置状态
            RefundManagement refundManagement = refundManagementService.get(id);
            if (refundManagement.getFinancingAmount().compareTo(BigDecimal.ZERO) == 1) {
                refundManagementService.lambdaUpdate().eq(RefundManagement::getId, id)
                        .set(RefundManagement::getRefundStatus, ProjectInitiationStatusDict.ChildEnum.COMPLETED.getCode())
                        .set(RefundManagement::getStage, null)
                        .update();
            } else {
                refundManagementService.lambdaUpdate().eq(RefundManagement::getId, id)
                        .set(RefundManagement::getRefundStatus, null)
                        .set(RefundManagement::getStage, null)
                        .update();
            }
        }
    }

    @Override
    public void handleCashFlow(BillingNonbusinessManageFactoringentry nobusinessManage) {
        if (nobusinessManage != null) {
            RefundsApplyDetails refundsApplyDetails = refundsApplyDetailsService.getById(nobusinessManage.getTradeRefundManagementId());
            cashFlowComplete(refundsApplyDetails, nobusinessManage);
        }
    }

    private void updateStatus(RefundManagementApproval approval) {

        Integer status = 1;
        if (approval.getApprovalConclusion().equals(ConstantConversionUtil.APPROVAL_RESULT_BACK)) {
            //退回
            status = 2;
        }
        refundDetailsService.lambdaUpdate().eq(RefundDetails::getRefundManagementId, approval.getRefundManagementId())
                .set(RefundDetails::getStatus, status).update();
        List<RefundsApplyDetails> applyDetailsList = refundsApplyDetailsService.lambdaQuery()
                .eq(RefundsApplyDetails::getRefundManagementId, approval.getRefundManagementId())
                .eq(RefundsApplyDetails::getStatus, 0).list();

        if (CollectionUtil.isNotEmpty(applyDetailsList)) {
            for (RefundsApplyDetails applyDetails : applyDetailsList) {
                refundsApplyAccountInfoService.lambdaUpdate().eq(RefundsApplyAccountInfo::getRefundsApplyDetailsId, applyDetails.getId())
                        .eq(RefundsApplyAccountInfo::getStatus, 0)
                        .set(RefundsApplyAccountInfo::getStatus, status).update();
            }
        }
        refundsApplyDetailsService.lambdaUpdate().eq(RefundsApplyDetails::getRefundManagementId, approval.getRefundManagementId())
                .eq(RefundsApplyDetails::getStatus, 0)
                .set(RefundsApplyDetails::getStatus, status).update();

        refundManagementPayCollPlanFactoringRefService.lambdaUpdate().eq(RefundManagementPayCollPlanFactoringRef::getRefundManagementId, approval.getId())
                .eq(RefundManagementPayCollPlanFactoringRef::getStatus, 0)
                .set(RefundManagementPayCollPlanFactoringRef::getStatus, status)
                .update();

    }

    private void handleProcess(RefundManagementApproval approval) {

        RefundManagement management = refundManagementService.lambdaQuery().eq(RefundManagement::getId, approval.getRefundManagementId()).one();

        Map<String, Object> msgVariables = new HashMap<>(2);
        msgVariables.put(ConstantUtil.FLOWABLE_MSG_TITLE, management.getBusinessNumber());
        msgVariables.put(ConstantUtil.FLOWABLE_MSG_CONTENT,
                "业务编号为" + management.getBusinessNumber() + "”的项目已inOut“"
                        + ConstantConversionUtil.flowBusinessKeyNames.get(management.getId()) + "—formBusiness”阶段，");

        Boolean success = flowableService.completeMyTask(approval.getTaskId(), management, null,
                ConstantConversionUtil.processApprovalResult.get(approval.getApprovalConclusion()), approval.getId(), msgVariables,
                ConstantUtil.REFUND_MANAGEMENT);
        if (success == null || !success) {
            throw new ValidatorException(CodeUtil.FAIL, "退款管理合同审批出错啦！");
        }
    }

    /**
     * 闭合 现金流-出账 状态
     *
     * @param applyDetail
     */
    private void cashFlowComplete(RefundsApplyDetails applyDetail, BillingNonbusinessManageFactoringentry nobusinessManage) {
        //现金流对应出账信息置为已完成
        List<RefundsApplyDetailsPayCollPlanRef> detailsPayCollPlanRefs = refundsApplyDetailsPayCollPlanRefService.lambdaQuery()
                .eq(RefundsApplyDetailsPayCollPlanRef::getRefundsApplyDetailsId, applyDetail.getId())
                .list();
        //现金流对应金额类型为 履约保证金 质保金 实退金额
        List<RefundDetailsRefundsApplyDetailsRef> applyDetailsRefs = refundDetailsRefundsApplyDetailsRefService.lambdaQuery()
                .eq(RefundDetailsRefundsApplyDetailsRef::getRefundsApplyDetailsId, applyDetail).list();
        if (CollectionUtil.isNotEmpty(applyDetailsRefs)) {
            for (RefundDetailsRefundsApplyDetailsRef applyDetailsRef : applyDetailsRefs) {
                RefundDetails refundDetails = refundDetailsService.lambdaQuery()
                        .eq(RefundDetails::getId, applyDetailsRef.getRefundDetailsId()).one();
                List<CashFlowManageBasicInfo> flowManageBasicInfoList = cashFlowManageBasicInfoService.lambdaQuery()
                        .eq(CashFlowManageBasicInfo::getLedgerFundGoodsAssignId, refundDetails.getLedgerFundGoodsAssignId())
                        .eq(CashFlowManageBasicInfo::getEntryOutType, 2)
                        .list();
                if (CollectionUtil.isNotEmpty(flowManageBasicInfoList)) {

                    List<CashFlowManageBasicInfo> cashFlowManageBasicInfos = flowManageBasicInfoList.stream()
                            .filter(flowManageBasicInfo -> (flowManageBasicInfo.getCashType().equals(CashFlowOutTypeDict.ChildEnum.DISCOUNT.getCode()))
                                    || flowManageBasicInfo.getCashType().equals(CashFlowOutTypeDict.ChildEnum.PERFORMANCE_BOND.getCode())
                                    || flowManageBasicInfo.getCashType().equals(CashFlowOutTypeDict.ChildEnum.RETENTION_MONEY.getCode()))
                            .collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(cashFlowManageBasicInfos)) {
                        cashFlowManageBasicInfos.forEach(cashFlowManageBasicInfo -> {
                            if (refundDetails.getAmountType().equals(cashFlowManageBasicInfo.getCashType())) {
                                if (nobusinessManage != null) {
                                    //补充出账信息
                                    saveCashFlowOut(nobusinessManage, cashFlowManageBasicInfo.getId());
                                }
                                cashFlowManageBasicInfoService.lambdaUpdate().eq(CashFlowManageBasicInfo::getId, cashFlowManageBasicInfo.getId())
                                        .set(CashFlowManageBasicInfo::getCashStatus, 4).update();
                            }
                        });
                    }
                }

            }
        }

        //计划
        if (CollectionUtil.isNotEmpty(detailsPayCollPlanRefs)) {
            for (RefundsApplyDetailsPayCollPlanRef detailsPayCollPlanRef : detailsPayCollPlanRefs) {
                CashFlowManageBasicPayCollPlanRef cashFlowManageBasicPayCollPlanRef = cashFlowManageBasicPayCollPlanRefService
                        .lambdaQuery()
                        .eq(CashFlowManageBasicPayCollPlanRef::getPayCollPlanFactoringId, detailsPayCollPlanRef.getPayCollPlanFactoringId())
                        .one();
                if (cashFlowManageBasicPayCollPlanRef != null) {
                    saveCashFlowOut(nobusinessManage, cashFlowManageBasicPayCollPlanRef.getCashFlowManageBasicInfoId());
                    cashFlowManageBasicInfoService.lambdaUpdate()
                            .eq(CashFlowManageBasicInfo::getId, cashFlowManageBasicPayCollPlanRef.getCashFlowManageBasicInfoId())
                            .set(CashFlowManageBasicInfo::getCashStatus, 4).update();
                }
            }
        }
    }

    /**
     * 根据贸易公司填充银行卡号
     *
     * @param cashFlowRequest
     */
    private void autoBankInfo(AddCashFlowRequest cashFlowRequest, Long tradingPlatformId) {

        Platform platform = platformService.getById(tradingPlatformId);
        if (platform.getPlatformName().equals("上海敖洪商贸有限公司")) {
            cashFlowRequest.setBankAccountId(227L);
            cashFlowRequest.setBankAccount("00000001");
            cashFlowRequest.setBankName("上海敖洪退款抵扣虚拟账户");
        }

        if (platform.getPlatformName().equals("西安长银保国际贸易有限公司")) {
            cashFlowRequest.setBankAccountId(228L);
            cashFlowRequest.setBankAccount("00000002");
            cashFlowRequest.setBankName("西安长银保退款抵扣虚拟账户");
        }

        if (platform.getPlatformName().equals("陕西卡服保贸易有限公司")) {
            cashFlowRequest.setBankAccountId(229L);
            cashFlowRequest.setBankAccount("00000003");
            cashFlowRequest.setBankName("陕西卡服保退款抵扣虚拟账户");
        }

        if (platform.getPlatformName().equals("深圳长银保国际贸易有限公司")) {
            cashFlowRequest.setBankAccountId(230L);
            cashFlowRequest.setBankAccount("00000004");
            cashFlowRequest.setBankName("深圳长银保退款抵扣虚拟账户");
        }

        if (platform.getPlatformName().equals("上海颗服保贸易有限公司")) {
            cashFlowRequest.setBankAccountId(231L);
            cashFlowRequest.setBankAccount("00000005");
            cashFlowRequest.setBankName("上海颗服保退款抵扣虚拟账户");
        }

    }

    /**
     * 保存现金流出账信息
     *
     * @param nobusinessManage
     * @param cashFlowManageBasicInfoId
     */
    void saveCashFlowOut(BillingNonbusinessManageFactoringentry nobusinessManage, Long cashFlowManageBasicInfoId) {
        CashFlowManageOutInfo flowManageOutInfo = new CashFlowManageOutInfo();
        flowManageOutInfo.setCashFlowManageBasicInfoId(cashFlowManageBasicInfoId);
        flowManageOutInfo.setLoanDate(nobusinessManage.getBillDate());
        flowManageOutInfo.setLoanAmount(nobusinessManage.getAmountMoney());
        //公司归属
        BankAccountInfo bankAccountInfo = nobusinessManage.getBankAccountInfo();
        Dictionary companyBelong = dictionaryService.getByCode(bankAccountInfo.getCompanyOwnership().getCode());
        flowManageOutInfo.setFromCompanyBelong(companyBelong.getId());
        flowManageOutInfo.setFromBankName(bankAccountInfo.getBankName());
        flowManageOutInfo.setFromBankAccount(bankAccountInfo.getBankCardNo());
        flowManageOutInfo.setCurrExecutor(nobusinessManage.getExecutor().getName());
        flowManageOutInfo.setFileText("");
        cashFlowManageOutInfoService.save(flowManageOutInfo);
    }


}
