package com.jwipc.finance.logic.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jwipc.aggregation.ModelAggregationService;
import com.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.ApiResult;
import com.jwipc.api.dto.OaFileParamDTO;
import com.jwipc.constant.DictCode;
import com.jwipc.constant.OaProcessType;
import com.jwipc.db.DbUtil;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.constant.DEDUCTIONTYPE;
import com.jwipc.finance.constant.DeductionOaClient;
import com.jwipc.finance.constant.STATUS;
import com.jwipc.finance.constant.SequenceConst;
import com.jwipc.finance.convert.DeductionConvert;
import com.jwipc.finance.dto.DeductionDTO;
import com.jwipc.finance.dto.DeductionExportDTO;
import com.jwipc.finance.dto.DeductionImportDTO;
import com.jwipc.finance.entity.Deduction;
import com.jwipc.finance.logic.DeductionLogic;
import com.jwipc.finance.model.param.DeductionParam;
import com.jwipc.finance.model.po.DeductionPO;
import com.jwipc.finance.model.po.ReceiveVoucherPO;
import com.jwipc.finance.model.query.DeductionExportQuery;
import com.jwipc.finance.model.query.DeductionQuery;
import com.jwipc.finance.service.IDeductionService;
import com.jwipc.finance.service.IReceiveVoucherService;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.client.*;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.FileResposePreviewCDTO;
import com.jwipc.sys.client.dto.UserDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;
import static com.jwipc.util.DateUtils.yyyyMMdd;

/**
 * @author Al
 * @create 2024-02-20 16:28
 * 对账管理-扣款管理
 */
@Service
@RequiredArgsConstructor
public class DeductionLogicImpl implements DeductionLogic {
    private final IDeductionService deductionService;
    private final DeductionConvert deductionConvert;
    private final UserClient userClient;
    private final DeductionOaClient deductionOaClient;
    private final PurchaseGroupClient purchaseGroupClient;
    private final DictClient dictClient;
    private final FileClient fileClient;
    private final ModelAggregationService modelAggregationService;
    private final IReceiveVoucherService receiveVoucherService;
    @Override
    @DS(SLAVE)
    public PageView findByPage(DeductionQuery query) {
        final Page<Deduction> dbPage = PageUtil.toPage(query);
        //增加按关系PO号查询
        if (StringUtils.isNotEmpty(query.getErpSyncNo())) {
            query.setErpSyncNo(DbUtil.toRegexp(query.getErpSyncNo()));
        }

        List<DeductionPO> deductionPOS = deductionService.findPageByQuery(dbPage, query);
        for (DeductionPO deductionPO : deductionPOS) {
            if(Objects.nonNull(deductionPO.getErpSyncNo())){
                ReceiveVoucherPO receiveVoucherPO = receiveVoucherService.findByErpSyncNo(deductionPO.getErpSyncNo());
                if(Objects.nonNull(receiveVoucherPO)){
                deductionPO.setStatementOrderCode(receiveVoucherPO.getAsNo());

                }
            }
        }
        List<Deduction> deductions = deductionConvert.po2PageListEntities(deductionPOS);
        deductionService.saveOrUpdateBatch(deductions);
        List<DeductionPO> deductionPOS1 = deductionService.findPageByQuery(dbPage, query);


        return PageUtil.getPV(deductionConvert.po2PageListDTO(deductionPOS1), dbPage.getTotal());
    }
    @Override
    public DeductionDTO getById(Long id) {
        if (id != null) {
            DeductionPO deductionPO = deductionService.getDataById(id);
            //List<DeductionDTO> deductionDTO = deductionConvert.assistantSupplierPO2DTOList(deductionPO);
            DeductionDTO deductionDTO = deductionConvert.po2DTO(deductionPO);
            modelAggregationService.processRelationAggregation(deductionDTO);
            //return deductionConvert.po2DTO(deductionPO);
            return deductionDTO;
        }else{
            return new DeductionDTO();
        }
    }
//扣款单确认保存
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateConfirm(DeductionParam param) {
        if(StringUtils.isNotEmpty(param.getDeductionTimeDesc())){
            param.setDeductionTime(LocalDateTimeUtil.parse(param.getDeductionTimeDesc(),"yyyy-MM-dd"));
        }
        //保存
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).ne(Deduction::getId, param.getId()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setUpdateUserId(LoginUtil.getUserId());
            param.setUpdateUserName(LoginUtil.getName());
            param.setStatus(6);
            param.setUpdateTime(LocalDateTime.now());

        deductionService.saveOrUpdate(deductionConvert.param2Entity(param));
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdate(DeductionParam param,String sequenceNo) {
        if(StringUtils.isNotEmpty(param.getDeductionTimeDesc())){
            param.setDeductionTime(LocalDateTimeUtil.parse(param.getDeductionTimeDesc(),"yyyy-MM-dd"));
        }

        //保存
        if (Objects.isNull(param.getId())) {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setId(null);
            //创建枚举类，获取单号
            param.setDeductionNo(sequenceNo);
            param.setCreateUserId(LoginUtil.getUserId());
            param.setCreateUserName(LoginUtil.getName());
            param.setStatus(0);
            param.setCreateTime(LocalDateTime.now());
        } else {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).ne(Deduction::getId, param.getId()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setUpdateUserId(LoginUtil.getUserId());
            param.setUpdateUserName(LoginUtil.getName());
            param.setUpdateTime(LocalDateTime.now());
            deductionService.saveOrUpdate(deductionConvert.param2Entity(param));
            if(param.getFlag() == 5){
            submitOa(String.valueOf(param.getId()));
            }
        }
        deductionService.saveOrUpdate(deductionConvert.param2Entity(param));
    }

    //列表主数据
    @Override
    public List<DeductionDTO> listAll(DeductionQuery query) {
        List<DeductionPO> deductionPOS = deductionService.findPageByQuery(null, query);
        return deductionConvert.po2PageListDTO(deductionPOS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refuse(DeductionParam param,String sequenceNo) {
        if(StringUtils.isNotEmpty(param.getDeductionTimeDesc())){
            param.setDeductionTime(LocalDateTimeUtil.parse(param.getDeductionTimeDesc(),"yyyy-MM-dd"));
        }

        //保存
        if (Objects.isNull(param.getId())) {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setId(null);
            //创建枚举类，获取单号
            param.setDeductionNo(sequenceNo);
            param.setCreateUserId(LoginUtil.getUserId());
            param.setCreateUserName(LoginUtil.getName());
            //param.setStatus(5);
            param.setCreateTime(LocalDateTime.now());
        } else {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).ne(Deduction::getId, param.getId()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setStatus(5);
            param.setUpdateUserId(LoginUtil.getUserId());
            param.setUpdateUserName(LoginUtil.getName());
            param.setUpdateTime(LocalDateTime.now());
        }
        deductionService.saveOrUpdate(deductionConvert.param2Entity(param));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(DeductionParam param,String sequenceNo) {
        if(StringUtils.isNotEmpty(param.getDeductionTimeDesc())){
            param.setDeductionTime(LocalDateTimeUtil.parse(param.getDeductionTimeDesc(),"yyyy-MM-dd"));
        }

        //保存
        if (Objects.isNull(param.getId())) {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            param.setId(null);
            //创建枚举类，获取单号
            param.setDeductionNo(sequenceNo);
            param.setCreateUserId(LoginUtil.getUserId());
            param.setCreateUserName(LoginUtil.getName());
            if(param.getFlag() == 3){
                param.setStatus(6);
            }else{
                param.setStatus(4);
            }
            param.setCreateTime(LocalDateTime.now());

        } else {
            final LambdaQueryWrapper<Deduction> resourcesLambdaQueryWrapper = new LambdaQueryWrapper<Deduction>().eq(
                    Deduction::getDeductionNo, param.getDeductionNo()).ne(Deduction::getId, param.getId()).last(" limit 1");
            if (ObjectUtil.isNotNull(deductionService.getOne(resourcesLambdaQueryWrapper))) {
                throw new DaoException("产品料号重复");
            }
            if(param.getFlag() == 4){
                param.setStatus(6);
            }else{
                param.setStatus(4);
            }
            param.setUpdateUserId(LoginUtil.getUserId());
            param.setUpdateUserName(LoginUtil.getName());
            param.setUpdateTime(LocalDateTime.now());
        }
        deductionService.saveOrUpdate(deductionConvert.param2Entity(param));
    }
    //线下使用
    @Override
    public void whether(Long id, Integer whether) {
        Deduction deduction = new Deduction();
        deduction.setId(id);
        deduction.setWhether(whether);
        deductionService.updateById(deduction);
    }
    //导出(未成功)
    @Override
    public List<DeductionExportDTO> getDeductionForExport(DeductionExportQuery query) {
        final LambdaQueryWrapper<Deduction> queryWrapper = getQueryWrapper(
                query);
        final List<Deduction> list = deductionService.list(queryWrapper);
        final List<DeductionExportDTO> list1 = deductionConvert.entites2ExportDTOs(list);
        for (DeductionExportDTO deductionExportDTO : list1) {
            deductionExportDTO.setStatusName(STATUS.forType(deductionExportDTO.getStatus()).getName());
            deductionExportDTO.setDeductionTypeName(DEDUCTIONTYPE.forType(deductionExportDTO.getDeductionType()).getName());
//            deductionExportDTO.setDeductionTimeStr(deductionExportDTO.getDeductionTime()));
//            deductionExportDTO.setDeductionTime(LocalDateTimeUtil.parse(deductionExportDTO.getDeductionTimeStr(),"yyyy-MM-dd"));
        }

        return list1;
    }

    @Override
    public void submitOa(String id) {
        Deduction deduction = deductionService.getById(id);
        DeductionImportDTO deductionImportDTO = new DeductionImportDTO();
        DeductionImportDTO.Head head = new DeductionImportDTO.Head();
        //SRM单据唯一编号
        head.setRecordId(deduction.getDeductionNo());
        //OA流程ID
        head.setProcessId(StringUtils.isEmpty(deduction.getOaCode())?"":deduction.getOaCode());
        //SRM业务类型 1 新增 2修改
//        head.setSRMToS(StringUtils.isEmpty(deduction.getOaCode())?"1":"2");
        head.setSRMToS(String.valueOf(OaProcessType.DEDUCTION.getType()));
        UserDTO userDTO = userClient.getByUserId(deduction.getCreateUserId());
        //申请人
        head.setApplicant(userDTO.getAccountName());
        //申请日期
        head.setApplyDate(LocalDateTimeUtil.format(deduction.getCreateTime(),"yyyy-MM-dd"));
        //TODO 扣款执行采购 给用户编号，不要存名字
        UserDTO userDTO2 = userClient.getByName(purchaseGroupClient.getByCode(String.valueOf(deduction.getDeductionExecutionProcurement())).getPurchaseGroupName());
       if(Objects.nonNull(userDTO2)){
           head.setExecuteProcure(userDTO2.getAccountName());
       }
        //责任厂商代码
        head.setVendorCode(deduction.getSupplierCode());
        //责任厂商名称
        head.setTradeName(deduction.getSupplierName());
        //质量异常描述
        head.setQualityAbnormal(deduction.getDeductionReason());
        //预扣款金额（小写）
        head.setDeductionAmount(deduction.getDeductionAmount());
        //TODO 币种 没取到，先默认CNY
//        head.setCurrency(deduction.getCurrency());
        head.setCurrency(deduction.getCurrency());
        //预扣款金额（大写）
        head.setDeductionAmountWords(Convert.digitToChinese(deduction.getDeductionAmount()));
        //扣款科目
        DictDTO dictDTO = dictClient.getDictByTypeAndCode(DictCode.BACK_TYPE.getCode(), String.valueOf(deduction.getDeductionType()));
        head.setDeductionSubject(dictDTO.getName());
        //TODO 扣款科目（扣款类型）选了其他则该项必填 页面需要处理
        head.setOtherDeductionSubject("其他");
        UserDTO userDTO1 = userClient.getByUserId(deduction.getApAccountant());
        //TODO 应付会计 给用户编号，不要存名字
        if(Objects.nonNull(userDTO1)){
            head.setApAccountant(userDTO1.getAccountName());
        }

        //实际扣款金额（小写）
        head.setActualDeductionAmount(deduction.getDntAmount());
        //币种1
        //TODO 币种 没取到，先默认CNY
//        head.setCurrency1(deduction.getCurrency());
        head.setCurrency1(deduction.getCurrency());
        //实际扣款金额（大写）
        head.setActualDeductionAmountWords(Convert.digitToChinese(deduction.getDntAmount()));
        //采购组
        head.setPurchaseGroupCode(deduction.getDeductionExecutionProcurement().toString());
        //公司代码
        head.setCompanyCode(deduction.getCompanyCode());
        //工厂
        head.setFactoryCode(deduction.getFactory());
        //税率编码
        head.setTaxCode(deduction.getTaxCode());
        if (StringUtils.isNotEmpty(deduction.getAttachment())){
            List<FileResposePreviewCDTO> fileResposePreviewDTOS = fileClient.getPreviewUrl(Arrays.asList(StringUtils.split(deduction.getAttachment(), ",")));
            List<String> strings = fileResposePreviewDTOS.stream().map(FileResposePreviewCDTO::getPreviewUrl).toList();
            List<OaFileParamDTO> list1 = new ArrayList<>();
            for (FileResposePreviewCDTO fileResposePreviewDTO : fileResposePreviewDTOS) {
                OaFileParamDTO build = OaFileParamDTO.builder().fileName(fileResposePreviewDTO.getFileName()).url(fileResposePreviewDTO.getPreviewUrl())
                        .downloadUrl(fileResposePreviewDTO.getDownloadUrl()).build();
                list1.add(build);
            }
            //相关附件未盖章文件
//            final FileResposeDTO fileResposeDTO = fileCache.get(tmp.getFileId());
//            if (Objects.nonNull(fileResposeDTO)) {
//                final OaFileParamDTO build = OaFileParamDTO.builder().url(fileResposeDTO.getPreviewUrl())
//                        .fileName(fileResposeDTO.getFileName()).build();
//                head.setFd_ckUrl(JSON.toJSONString(Lists.newArrayList(build)));//出口许可证附件
//            }
//            head.setFd_ckDate(tmp.getAvailableEndDate());//出口许可证（适用于海外供应商）有效期
//            head.setRelatedAnnex(String.join(",", strings));
            head.setRelatedAnnex(JSON.toJSONString(list1));
        }else {
            //相关附件未盖章文件
            head.setRelatedAnnex("");
        }
        if (StringUtils.isNotEmpty(deduction.getSupReplyAttachment())){
            List<FileResposePreviewCDTO> fileResposePreviewDTOS = fileClient.getPreviewUrl(Arrays.asList(StringUtils.split(deduction.getSupReplyAttachment(), ",")));
            List<String> strings = fileResposePreviewDTOS.stream().map(FileResposePreviewCDTO::getPreviewUrl).toList();
            //相关附件盖章文件
            List<OaFileParamDTO> list2 = new ArrayList<>();
            for (FileResposePreviewCDTO fileResposePreviewDTO : fileResposePreviewDTOS) {
                OaFileParamDTO build = OaFileParamDTO.builder().fileName(fileResposePreviewDTO.getFileName())
                        .downloadUrl(fileResposePreviewDTO.getDownloadUrl()).url(fileResposePreviewDTO.getPreviewUrl()).build();
                list2.add(build);
            }
//            head.setSealRelatedAnnex(String.join(",", strings));
            head.setSealRelatedAnnex(JSON.toJSONString(list2));
        }else {
            //相关附件盖章文件
            head.setSealRelatedAnnex("");
        }
        deductionImportDTO.setHead(head);
        ApiResult<String>  orUpdate = deductionOaClient.deductionImport(deductionImportDTO);
        final String code = orUpdate.getCode();
        if (code.equals(RestCode.SAP_SUCCESS.getCode())) {
            //成功就更新流程id
            final String oaId = orUpdate.getData();
            deduction.setOaCode(oaId);
            deduction.setStatus(1);
            deductionService.updateById(deduction);
        } else {
            throw new DaoException(StrUtil.format("OA接口报错：{}",orUpdate.getMessage()));
        }
    }

    @NotNull
    private static LambdaQueryWrapper<Deduction> getQueryWrapper(
            DeductionExportQuery query)
    {
        final LambdaQueryWrapper<Deduction> queryWrapper = new LambdaQueryWrapper<>();
        if(query.getWhether() != -1){
        queryWrapper.eq(Objects.nonNull(query.getWhether()), Deduction::getWhether,
                query.getWhether());
        }
        queryWrapper.like(StrUtil.isNotEmpty(query.getDeductionNo()), Deduction::getDeductionNo,
                query.getDeductionNo());
        queryWrapper.eq(Objects.nonNull(query.getDeductionType()), Deduction::getDeductionType,
                query.getDeductionType());
        queryWrapper.like(StrUtil.isNotEmpty(query.getTaxCode()), Deduction::getTaxCode,
                query.getTaxCode());
        queryWrapper.eq(Objects.nonNull(query.getDntAmount()), Deduction::getDntAmount,
                query.getDntAmount());
        queryWrapper.eq(Objects.nonNull(query.getDeductionAmount()), Deduction::getDeductionAmount,
                query.getDeductionAmount());
//        queryWrapper.like(StrUtil.isNotEmpty(query.getDntAmount().toString()), Deduction::getDntAmount,
//                query.getDntAmount());
//        queryWrapper.like(StrUtil.isNotEmpty(query.getDeductionAmount().toString()), Deduction::getDeductionAmount,
//                query.getDeductionAmount());
            queryWrapper.like(StrUtil.isNotEmpty( LocalDateTimeUtil.format(query.getDeductionTime(),yyyyMMdd)), Deduction::getDeductionTime,
                    query.getDeductionTime());
//        queryWrapper.like(StrUtil.isNotEmpty(query.getDeductionTimeDesc()), Deduction::getDeductionTime,
//                query.getDeductionTimeDesc());
        queryWrapper.like(StrUtil.isNotEmpty(query.getDeductionReason()), Deduction::getDeductionReason,
                query.getDeductionReason());
        queryWrapper.like(StrUtil.isNotEmpty(query.getSupplierCode()), Deduction::getSupplierCode,
                query.getSupplierCode());
        queryWrapper.like(StrUtil.isNotEmpty(query.getSupplierName()), Deduction::getSupplierName,
                query.getSupplierName());
        queryWrapper.like(StrUtil.isNotEmpty(query.getCompanyCode()), Deduction::getCompanyCode,
                query.getCompanyCode());
        queryWrapper.like(StrUtil.isNotEmpty(query.getCompanyName()), Deduction::getCompanyName,
                query.getCompanyName());
        queryWrapper.like(StrUtil.isNotEmpty(query.getAssociatedNo()), Deduction::getAssociatedNo,
                query.getAssociatedNo());
        queryWrapper.like(StrUtil.isNotEmpty(query.getAssociatedRowNo()), Deduction::getAssociatedRowNo,
                query.getAssociatedRowNo());
        queryWrapper.like(StrUtil.isNotEmpty(query.getCreateUserName()), Deduction::getCreateUserName,
                query.getCreateUserName());
        queryWrapper.like(StrUtil.isNotEmpty( LocalDateTimeUtil.format(query.getCreateTime(),yyyyMMdd)), Deduction::getCreateTime,
                query.getCreateTime());
        if (query.getErpSyncState()!=null){
            queryWrapper.eq(Objects.nonNull(query.getErpSyncState()), Deduction::getErpSyncState,
                    query.getErpSyncState());
//            map.put("ERP处理状态", dm.getErpSyncState()==1?"失败":"成功");
        }else {
//            queryWrapper.eq(Objects.nonNull(query.getErpSyncState()), Deduction::getErpSyncState,
//                    query.getErpSyncState());
//            map.put("ERP处理状态", "");
        }
        queryWrapper.like(StrUtil.isNotEmpty(query.getErpSyncMessage()), Deduction::getErpSyncMessage,
                query.getErpSyncMessage());
        queryWrapper.like(StrUtil.isNotEmpty(query.getErpSyncNo()), Deduction::getErpSyncNo,
                query.getErpSyncNo());
        queryWrapper.like(StrUtil.isNotEmpty(query.getErpSyncYear()), Deduction::getErpSyncYear,
                query.getErpSyncYear());
        queryWrapper.like(StrUtil.isNotEmpty( LocalDateTimeUtil.format(query.getErpSyncTime(),yyyyMMdd)), Deduction::getErpSyncTime,
                query.getErpSyncTime());
//        queryWrapper.eq(Objects.nonNull(query.getDeleteFlag()), Deduction::getDeleteFlag,
//                query.getDeleteFlag());
        return queryWrapper;
    }
    //删除
    @Override
    public void remove(String id) {
        deductionService.remove(new LambdaQueryWrapper<Deduction>().eq(Deduction::getId, id));
    }

}
