package cn.superdesk.uniorder.service.thirdpart.qchjc.statistics.impl;

import cn.hutool.core.io.FileUtil;
import cn.superdesk.uniorder.common.enums.statistics.StatisticsBalanceCustomerTypeEnum;
import cn.superdesk.uniorder.common.enums.statistics.StatisticsBalanceQueryEnum;
import cn.superdesk.uniorder.common.enums.thirdpart.jd.SysQuartzScheduleTaskStatementOfAccountRunStateEnum;
import cn.superdesk.uniorder.common.excel.ExcelResponse;
import cn.superdesk.uniorder.common.numerical.AnDateUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.dao.entity.sys.notify.SysNotify;
import cn.superdesk.uniorder.dao.mapper._statistics.PayableStatisticsMapper;
import cn.superdesk.uniorder.dao.mapper._statistics.ReceivableStatisticsMapper;
import cn.superdesk.uniorder.dto._constant.ResourceConstant;
import cn.superdesk.uniorder.dto.param.accounting.statistics.PayableBalanceQueryParam;
import cn.superdesk.uniorder.dto.param.accounting.statistics.ReceivableBalanceQueryParam;
import cn.superdesk.uniorder.dto.vo._statistics.ReceivableBalanceDetail;
import cn.superdesk.uniorder.dto.vo._statistics.ReceivableBalanceVO;
import cn.superdesk.uniorder.dto.vo._statistics.ReceivableStatisticsDetailDataByExcelVo;
import cn.superdesk.uniorder.dto.vo._statistics.payable.PayableBalanceDetail;
import cn.superdesk.uniorder.dto.vo._statistics.payable.PayableBalanceVO;
import cn.superdesk.uniorder.dto.vo._statistics.payable.PayableStatisticsDayDataByExcelVo;
import cn.superdesk.uniorder.notify.NotifyUtils;
import cn.superdesk.uniorder.service.thirdpart.qchjc.statistics.BalanceStatistcsService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xc
 * @description 应收/应付 余额报表service
 * @date 2022/6/22 09:32
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BalanceStatistcsServiceImpl implements BalanceStatistcsService {
    private final ResourceConstant excelExportConstant;
    private final ReceivableStatisticsMapper receivableStatisticsMapper;
    private final PayableStatisticsMapper payableStatisticsMapper;
    //应收余额模板
    private static final String EXPORT_RECEIVABLE_BALANCE_TEMPLATE = "exportExcelReceivableBalanceTemplate.xls";
    //应付余额模板
    private static final String EXPORT_PAYABLE_BALANCE_TEMPLATE = "exportExcelPayableBalanceTemplate.xls";

    /**
     * 应收余额列表查询
     *
     * @param param
     * @return
     */
    @Override
    public R<ReceivableBalanceVO> getReceivableBalanceVOList(ReceivableBalanceQueryParam param) {

        PageHelper.startPage(param.getPageNumber(), param.getPageSize());
        //获得应收报表分页后的settlementId
        List<Long> settlementIdList = receivableStatisticsMapper.getSettlementIdsPage(param);
        PageInfo<Long> page = new PageInfo<Long>(settlementIdList);
        settlementIdList.add(1000000L);//零星客户id
        PageHelper.clearPage();

        param.setSettlementIds(settlementIdList);

        //列表查询
        List<ReceivableBalanceDetail> res = receivableStatisticsMapper.getReceivableBalanceVOList(param);
        //应收合计
        BigDecimal totalReceivableAmount = res.stream().map(ReceivableBalanceDetail::getReceivableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        //实收合计
        BigDecimal totalActualReceipt = res.stream().map(ReceivableBalanceDetail::getActualReceipt).reduce(BigDecimal.ZERO, BigDecimal::add);
        //期末余额合计
        BigDecimal totalEndingBalance = res.stream().map(ReceivableBalanceDetail::getEndingBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        int seq = 0;
        for (ReceivableBalanceDetail re : res) {
            re.setSeq(String.valueOf(++seq));
        }
        ReceivableBalanceVO receivableBalanceVO = new ReceivableBalanceVO();
        receivableBalanceVO.setReceivableBalanceList(res);
        receivableBalanceVO.setTotalReceivableAmount(totalReceivableAmount);
        receivableBalanceVO.setTotalActualReceipt(totalActualReceipt);
        receivableBalanceVO.setTotalEndingBalance(totalEndingBalance);
        return new R<>(param.getPageNumber(), param.getPageSize(), (int) page.getTotal(), receivableBalanceVO);

    }

    /**
     * 应收余额报表导出
     * @param param
     * @return
     */
    @Override
    public SysNotify exportExcelReceivableBalance(ReceivableBalanceQueryParam param) {
        //应收余额sheet，汇总数据
        List<ReceivableBalanceDetail> sheet0Data = getReceivableBalanceTotalExcelData(param);
        //应收帐款（非零星客户）
        param.setQueryType(StatisticsBalanceQueryEnum.应收.getKey());
        param.setCustomerType(StatisticsBalanceCustomerTypeEnum.非零星客户.getKey());
        List<ReceivableStatisticsDetailDataByExcelVo> sheet1Data = receivableStatisticsMapper.selectReceivableBalanceByCondition(param);
        //实收账款（非零星客户）
        param.setQueryType(StatisticsBalanceQueryEnum.实收.getKey());
        param.setCustomerType(StatisticsBalanceCustomerTypeEnum.非零星客户.getKey());
        List<ReceivableStatisticsDetailDataByExcelVo> sheet2Data = receivableStatisticsMapper.selectReceivableBalanceByCondition(param);
        //应收帐款（零星客户）
        param.setQueryType(StatisticsBalanceQueryEnum.应收.getKey());
        param.setCustomerType(StatisticsBalanceCustomerTypeEnum.零星客户.getKey());
        List<ReceivableStatisticsDetailDataByExcelVo> sheet3Data = receivableStatisticsMapper.selectReceivableBalanceByCondition(param);;
        //实收账款（零星客户）
        param.setQueryType(StatisticsBalanceQueryEnum.实收.getKey());
        param.setCustomerType(StatisticsBalanceCustomerTypeEnum.零星客户.getKey());
        List<ReceivableStatisticsDetailDataByExcelVo> sheet4Data = receivableStatisticsMapper.selectReceivableBalanceByCondition(param);;

        //sheet0 日期
        Map<String, Object> exportDate = handleDate(param.getStartDate(), param.getEndDate());

        String excelExportPathRoot = excelExportConstant.getPathRoot();
        String excelExportRelativePathTemplate = excelExportConstant.getPathTemplate();
        String excelExportRelativePathStorage = excelExportConstant.getPathStorage();

        String relativePath = File.separator + "excel" + File.separator + "statistic" + File.separator + "receivable" + File.separator;
        String templateRelativePath = excelExportPathRoot + excelExportRelativePathTemplate + relativePath;
        String templateFullPath = templateRelativePath + EXPORT_RECEIVABLE_BALANCE_TEMPLATE;

        String targetFullPath = excelExportPathRoot + excelExportRelativePathStorage;
        String targetFileName = "应收余额表_财务报表_导出" + ExcelResponse.addTail() + ".xlsx";
        String targetWriteFileFullPath = targetFullPath + relativePath + targetFileName;

        FileUtil.touch(targetWriteFileFullPath);

        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(targetWriteFileFullPath);
        ExcelWriter excelWriter = null;
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "应收余额表").build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "应收帐款（非零星客户）").build();
        WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "实收账款（非零星客户）").build();
        WriteSheet writeSheet3 = EasyExcel.writerSheet(3, "应收账款（零星客户）)").build();
        WriteSheet writeSheet4 = EasyExcel.writerSheet(4, "实收账款（零星客户）").build();

        excelWriter = excelWriterBuilder.withTemplate(templateFullPath).build();

        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build();
        excelWriter.fill(new FillWrapper("detail", sheet0Data), fillConfig, writeSheet0).fill(exportDate, writeSheet0);
        excelWriter.fill(new FillWrapper("detail", sheet1Data), fillConfig, writeSheet1);
        excelWriter.fill(new FillWrapper("detail", sheet2Data), fillConfig, writeSheet2);
        excelWriter.fill(new FillWrapper("detail", sheet3Data), fillConfig, writeSheet3);
        excelWriter.fill(new FillWrapper("detail", sheet4Data), fillConfig, writeSheet4);

        excelWriter.finish();

        return NotifyUtils.createSysNotify(targetFileName, relativePath + targetFileName, SysQuartzScheduleTaskStatementOfAccountRunStateEnum.成功);
    }

    /**
     * 应付余额报表导出
     * @param param
     * @return
     */
    @Override
    public SysNotify exportExcelPayableBalance(PayableBalanceQueryParam param) {
        //应付余额sheet，汇总数据
        List<PayableBalanceDetail> sheet0Data = getPayableBalanceTotalExcelData(param);
        //应付账款
        param.setQueryType(StatisticsBalanceQueryEnum.应付.getKey());
        List<PayableStatisticsDayDataByExcelVo> sheet1Data = payableStatisticsMapper.selectPayableBalanceByCondition(param);
        //实付账款
        param.setQueryType(StatisticsBalanceQueryEnum.实付.getKey());
        List<PayableStatisticsDayDataByExcelVo> sheet2Data = payableStatisticsMapper.selectPayableBalanceByCondition(param);
        //sheet0 日期
        Map<String, Object> exportDate = handleDate(param.getStartDate(), param.getEndDate());

        String excelExportPathRoot = excelExportConstant.getPathRoot();
        String excelExportRelativePathTemplate = excelExportConstant.getPathTemplate();
        String excelExportRelativePathStorage = excelExportConstant.getPathStorage();

        String relativePath = File.separator + "excel" + File.separator + "statistic" + File.separator + "payable" + File.separator;
        String templateRelativePath = excelExportPathRoot + excelExportRelativePathTemplate + relativePath;
        String templateFullPath = templateRelativePath + EXPORT_PAYABLE_BALANCE_TEMPLATE;
        String targetFullPath = excelExportPathRoot + excelExportRelativePathStorage;
        String targetFileName = "应付余额表_财务报表_导出" + ExcelResponse.addTail() + ".xlsx";
        String targetWriteFileFullPath = targetFullPath + relativePath + targetFileName;

        FileUtil.touch(targetWriteFileFullPath);
        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(targetWriteFileFullPath);
        ExcelWriter excelWriter = null;
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "应付余额表").build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "应收帐款").build();
        WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "实收账款").build();
        excelWriter = excelWriterBuilder.withTemplate(templateFullPath).build();

        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build();
        excelWriter.fill(new FillWrapper("detail", sheet0Data), fillConfig, writeSheet0).fill(exportDate, writeSheet0);
        excelWriter.fill(new FillWrapper("detail", sheet1Data), fillConfig, writeSheet1);
        excelWriter.fill(new FillWrapper("detail", sheet2Data), fillConfig, writeSheet2);
        excelWriter.finish();

        return NotifyUtils.createSysNotify(targetFileName, relativePath + targetFileName, SysQuartzScheduleTaskStatementOfAccountRunStateEnum.成功);
    }

    private List<PayableBalanceDetail> getPayableBalanceTotalExcelData(PayableBalanceQueryParam param) {
        PageHelper.startPage(param.getPageNumber(), param.getPageSize());
        List<Long> settlementIds = payableStatisticsMapper.getSettlementIdsPage(param);
        PageHelper.clearPage();

        param.setSettlementIds(settlementIds);
        List<PayableBalanceDetail> res = payableStatisticsMapper.getPayableBalanceVOList(param);
        int seq = 0;
        for (PayableBalanceDetail p : res) {
            p.setSeq(String.valueOf(++seq));
        }
        if (CollectionUtils.isNotEmpty(res)) {
            //应付合计
            BigDecimal totalPayableAmount = res.stream().map(PayableBalanceDetail::getPayableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //实付合计
            BigDecimal totalActualPay = res.stream().map(PayableBalanceDetail::getActualPay).reduce(BigDecimal.ZERO, BigDecimal::add);
            //期末余额合计
            BigDecimal totalEndingBalance = res.stream().map(PayableBalanceDetail::getEndingBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            PayableBalanceDetail total = PayableBalanceDetail.builder()
                    .seq("合计")
                    .settlementName("")
                    .serviceNoName("")
                    .payableAmount(totalPayableAmount)
                    .actualPay(totalActualPay)
                    .endingBalance(totalEndingBalance).build();
            res.add(total);
        }
        return res;
    }


    private List<ReceivableBalanceDetail> getReceivableBalanceTotalExcelData(ReceivableBalanceQueryParam param) {
        PageHelper.startPage(param.getPageNumber(), param.getPageSize());
        //获得应收报表分页后的settlementId
        List<Long> settlementIdList = receivableStatisticsMapper.getSettlementIdsPage(param);
        PageInfo<Long> page = new PageInfo<Long>(settlementIdList);
        settlementIdList.add(1000000L);//零星客户id
        PageHelper.clearPage();
        param.setSettlementIds(settlementIdList);
        //列表查询
        List<ReceivableBalanceDetail> res = receivableStatisticsMapper.getReceivableBalanceVOList(param);
        int seq = 0;
        for (ReceivableBalanceDetail re : res) {
            re.setSeq(String.valueOf(++seq));
        }
        if (CollectionUtils.isNotEmpty(res)) {
            //应收合计
            BigDecimal totalReceivableAmount = res.stream().map(ReceivableBalanceDetail::getReceivableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //实收合计
            BigDecimal totalActualReceipt = res.stream().map(ReceivableBalanceDetail::getActualReceipt).reduce(BigDecimal.ZERO, BigDecimal::add);
            //期末余额合计
            BigDecimal totalEndingBalance = res.stream().map(ReceivableBalanceDetail::getEndingBalance).reduce(BigDecimal.ZERO, BigDecimal::add);

            //合计
            ReceivableBalanceDetail total = ReceivableBalanceDetail.builder()
                    .seq("合计")
                    .settlementName("")
                    .serviceNoName("")
                    .receivableAmount(totalReceivableAmount)
                    .actualReceipt(totalActualReceipt)
                    .endingBalance(totalEndingBalance).build();
            res.add(total);
        }
        return res;
    }

    /**
     * sheet0中的日期
     * @param
     * @return
     */
    private Map<String, Object> handleDate(String start, String end) {
        Map<String, Object> map = new HashMap<>();
        String startDate = "";
        String endDate = "";
        String exportDate = "";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        if (StringUtils.isNotBlank(start)) {
            Date date = AnDateUtils.parseDate(start);
            startDate = simpleDateFormat.format(date);
        }
        if (StringUtils.isNotBlank(end)) {
            Date date = AnDateUtils.parseDate(end);
            endDate = simpleDateFormat.format(date);
        }

        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            exportDate = startDate + "-" + endDate;
        }else if (StringUtils.isNotBlank(startDate) && StringUtils.isBlank(endDate)){
            endDate = simpleDateFormat.format(new Date());
            exportDate = startDate + "-" + endDate;
        }else if (StringUtils.isBlank(startDate)){
            endDate = simpleDateFormat.format(new Date());
            exportDate = "截止" + endDate;
        }

        map.put("exportDate", exportDate);
        return map;
    }
    /**
     * 应付余额列表查询
     *
     * @param param
     * @return
     */
    @Override
    public R<PayableBalanceVO> getPayableBalanceVOList(PayableBalanceQueryParam param) {
        PageHelper.startPage(param.getPageNumber(), param.getPageSize());
        List<Long> settlementIds = payableStatisticsMapper.getSettlementIdsPage(param);
        PageInfo<Long> page = new PageInfo<Long>(settlementIds);
        PageHelper.clearPage();
        param.setSettlementIds(settlementIds);
        List<PayableBalanceDetail> res = payableStatisticsMapper.getPayableBalanceVOList(param);
        //应付合计
        BigDecimal totalPayableAmount = res.stream().map(PayableBalanceDetail::getPayableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        //实付合计
        BigDecimal totalActualPay = res.stream().map(PayableBalanceDetail::getActualPay).reduce(BigDecimal.ZERO, BigDecimal::add);
        //期末余额合计
        BigDecimal totalEndingBalance = res.stream().map(PayableBalanceDetail::getEndingBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        int seq = 0;
        for (PayableBalanceDetail r : res) {
            r.setSeq(String.valueOf(++seq));
        }
        PayableBalanceVO payableBalanceVO = new PayableBalanceVO();
        payableBalanceVO.setTotalPayableAmount(totalPayableAmount);
        payableBalanceVO.setTotalActualPay(totalActualPay);
        payableBalanceVO.setTotalEndingBalance(totalEndingBalance);
        payableBalanceVO.setPayableBalanceList(res);

        return new R<>(param.getPageNumber(), param.getPageSize(), (int) page.getTotal(), payableBalanceVO);
    }
}
