package com.jwipc.finance.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jwipc.constant.DictCode;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.CompanyInvoicedReceiptConvert;
import com.jwipc.finance.dto.CompanyInvoicedReceiptDTO;
import com.jwipc.finance.dto.CompanyInvoicedReceiptImportDTO;
import com.jwipc.finance.entity.AccountStatement;
import com.jwipc.finance.entity.CompanyInvoicedReceipt;
import com.jwipc.finance.logic.CompanyInvoicedReceiptLogic;
import com.jwipc.finance.model.po.CompanyInvoicedReceiptPO;
import com.jwipc.finance.model.query.InvoicedDetailQuery;
import com.jwipc.finance.service.ICompanyInvoicedReceiptService;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.dto.CurrentUserDTO;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.client.dto.DictDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author shenyang.ou
 * @date 2024/3/5 13:27
 * @desc
 */
@Service
@RequiredArgsConstructor
public class CompanyInvoicedReceiptLogicImpl implements CompanyInvoicedReceiptLogic {
    private final CompanyInvoicedReceiptConvert companyInvoicedReceiptConvert;
    private final ICompanyInvoicedReceiptService companyInvoicedReceiptService;
    private final DictClient dictClient;

    /**
     * 根据开票申请单ID获取关联发票数据
     *
     * @param iaId 开票申请单ID
     * @return 关联发票数据
     */
    @Override
    public List<CompanyInvoicedReceiptDTO> getInvoiceReceiptListByIaId(Long iaId) {
        List<CompanyInvoicedReceiptPO> companyInvoicedReceiptPOS = companyInvoicedReceiptService.getInvoiceReceiptListByIaId(iaId);;
        return companyInvoicedReceiptConvert.po2DTOList(companyInvoicedReceiptPOS);
    }

    /**
     * 关联或取消关联发票
     *
     * @param companyInvoicedReceiptData 发票数据
     * @param iaId                开票申请单ID
     * @param currentUser         当前用户
     */
    @Override
    public void operateInvoice(List<CompanyInvoicedReceiptDTO> companyInvoicedReceiptData, Long iaId, CurrentUserDTO currentUser) {
        if (CollUtil.isNotEmpty(companyInvoicedReceiptData)) {
            companyInvoicedReceiptData.forEach(e -> e.setIaId(iaId));
            List<Long> allIds = companyInvoicedReceiptData.stream().map(CompanyInvoicedReceiptDTO::getId).filter(Objects::nonNull).collect(Collectors.toList());
            List<CompanyInvoicedReceipt> existList = companyInvoicedReceiptService.list(Wrappers.lambdaQuery(CompanyInvoicedReceipt.class).eq(CompanyInvoicedReceipt::getIaId,iaId));
            List<Long> exitIds = existList.stream().map(CompanyInvoicedReceipt::getId).collect(Collectors.toList());
            List<Long> removeIds = exitIds.stream().filter(f -> !allIds.contains(f)).collect(Collectors.toList());

            // 删除
            if (CollUtil.isNotEmpty(removeIds)) {
                companyInvoicedReceiptService.removeBatchByIds(removeIds);
            }
            //判断本次发票号码是否重复
            List<CompanyInvoicedReceiptDTO> nonNullNameList = companyInvoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullNameList)){
                Map<String, List<CompanyInvoicedReceiptDTO>> ext = nonNullNameList.stream()
                        .collect(Collectors.groupingBy(CompanyInvoicedReceiptDTO::getInvoiceNumber))
                        .entrySet().stream()
                        .filter(entry -> entry.getValue().size() > 1)
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                if (ObjectUtil.isNotNull(ext)){
                    ext.forEach((key, value) -> {
                        throw new DaoException("发票号码："+key+"重复录入"+value.size()+"条，请删除其中"+(value.size()-1)+"条");
                    });
                }
            }
            //判断本次数电发票号码是否重复
            List<CompanyInvoicedReceiptDTO> nonNullElectronNameList = companyInvoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getElectronInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullElectronNameList)){
                Map<String, List<CompanyInvoicedReceiptDTO>> electronExt = nonNullElectronNameList.stream()
                        .collect(Collectors.groupingBy(CompanyInvoicedReceiptDTO::getElectronInvoiceNumber))
                        .entrySet().stream()
                        .filter(entry -> entry.getValue().size() > 1)
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                if (ObjectUtil.isNotNull(electronExt)){
                    electronExt.forEach((key, value) -> {
                        throw new DaoException("数电发票号码："+key+"重复录入"+value.size()+"条，请删除其中"+(value.size()-1)+"条");
                    });
                }
            }
            //判断发票号码是否重复
            for (CompanyInvoicedReceiptDTO companyInvoicedReceipt : companyInvoicedReceiptData){
                if(StrUtil.isNotEmpty(companyInvoicedReceipt.getInvoiceNumber())){
                    CompanyInvoicedReceipt companyInvoicedReceipt1 = companyInvoicedReceiptService.getExitDataByIaIdAndInvoiceNumber(iaId,companyInvoicedReceipt.getInvoiceNumber());
                    if (ObjectUtil.isNotNull(companyInvoicedReceipt1)){
                        throw new DaoException("发票号码："+companyInvoicedReceipt.getInvoiceNumber()+"在系统中已存在，不可录入");
                    }
                }

            }
            //判断数电发票号码是否重复
            for (CompanyInvoicedReceiptDTO companyInvoicedReceipt : companyInvoicedReceiptData){
                companyInvoicedReceipt.setDeleteFlag(0);
                if(StrUtil.isNotEmpty(companyInvoicedReceipt.getElectronInvoiceNumber())){
                    companyInvoicedReceipt.setElectronInvoiceNumber(companyInvoicedReceipt.getElectronInvoiceNumber().trim());//去除空格
                    CompanyInvoicedReceipt companyInvoicedReceipt1 = companyInvoicedReceiptService.getExitDataByIaIdAndElectronInvoiceNumber(iaId,companyInvoicedReceipt.getElectronInvoiceNumber());
                    if (ObjectUtil.isNotNull(companyInvoicedReceipt1)){
                        throw new DaoException("数电发票号码："+companyInvoicedReceipt.getElectronInvoiceNumber()+"在系统中已存在，不可录入");
                    }
                }
            }
            // 新增或编辑
            companyInvoicedReceiptService.saveOrUpdateBatch(companyInvoicedReceiptConvert.dto2EntityList(companyInvoicedReceiptData));

        }
    }

    @Override
    public PageView getInvoiceReceiptListByQuery(InvoicedDetailQuery query) {
        final Page<AccountStatement> dbPage = PageUtil.toPage(query);
        List<CompanyInvoicedReceiptPO> companyInvoicedReceiptPOS = companyInvoicedReceiptService.findPageByQuery(dbPage, query);
        List<CompanyInvoicedReceiptDTO> companyInvoicedReceiptDTOS = companyInvoicedReceiptConvert.po2PageListDTO(companyInvoicedReceiptPOS);
        return PageUtil.getPV(companyInvoicedReceiptDTOS, dbPage.getTotal());
    }

    @Override
    public List<CompanyInvoicedReceiptDTO> listAll(InvoicedDetailQuery query) {
        List<CompanyInvoicedReceiptPO> companyInvoicedReceiptPOS = companyInvoicedReceiptService.findPageByQuery(null, query);
        return companyInvoicedReceiptConvert.po2PageListDTO(companyInvoicedReceiptPOS);
    }

    @Override
    public void updateDeductionStatus(List<String> idList, String deductionStatus, String note) {
        List<CompanyInvoicedReceipt> companyInvoicedReceiptList = companyInvoicedReceiptService.listByIds(idList);
        if (CollectionUtils.isNotEmpty(companyInvoicedReceiptList)){
            for (CompanyInvoicedReceipt companyInvoicedReceipt : companyInvoicedReceiptList){
                companyInvoicedReceipt.setNote(note);
                companyInvoicedReceipt.setDeductionStatus(deductionStatus);
            }
        }
        companyInvoicedReceiptService.updateBatchById(companyInvoicedReceiptList);
    }

    @Override
    public List<CompanyInvoicedReceiptImportDTO> importData(MultipartFile file) {
        List<CompanyInvoicedReceiptImportDTO> cachedDataList = ListUtils.newArrayList();
        //币种
        List<DictDTO> currencys = dictClient.getDicByType(DictCode.CURRENCY.getCode());
        final Map<String, DictDTO> currencyCache = currencys.stream().collect(Collectors.toMap(DictDTO::getCode, a -> a));
        final Set<String> currencyCodes = currencyCache.keySet();
        try {
            EasyExcel.read(file.getInputStream(), CompanyInvoicedReceiptImportDTO.class,
                    new ReadListener<CompanyInvoicedReceiptImportDTO>() {
                        @Override
                        public void invoke(CompanyInvoicedReceiptImportDTO data, AnalysisContext context) {
                            final String currencyCode = data.getCurrencyCode();
                            final String deductionCodeTypeStr = data.getDeductionCodeTypeStr();
                            if (StringUtils.isNotEmpty(deductionCodeTypeStr)&&"可抵扣".equals(deductionCodeTypeStr)){
                                data.setDeductionCodeType(1);
                            }
                            if (StringUtils.isNotEmpty(deductionCodeTypeStr)&&"不可抵扣".equals(deductionCodeTypeStr)){
                                data.setDeductionCodeType(2);
                            }
                            if (StringUtils.isNotEmpty(currencyCode)&&!currencyCodes.contains(currencyCode)){
                                throw new DaoException(StrUtil.format("币种：{}在系统中不存在",currencyCode));
                            }
                            cachedDataList.add(data);
                        }
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new DaoException("导入失败！");
        }
        return cachedDataList;
    }
}
