package com.artfess.cqlt.manager.impl;

import com.alibaba.fastjson.JSONObject;
import com.artfess.base.enums.DelStatusEnum;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.util.DateUtils;
import com.artfess.base.util.StringUtil;
import com.artfess.cqlt.dao.QfEnterpriseInfoDao;
import com.artfess.cqlt.dao.QfFinanceLiquidityDetailDao;
import com.artfess.cqlt.dao.QfFinanceLiquidityMDao;
import com.artfess.cqlt.manager.QfFinanceLiquidityDetailManager;
import com.artfess.cqlt.model.QfEnterpriseInfo;
import com.artfess.cqlt.model.QfFinanceLiquidityDetail;
import com.artfess.cqlt.model.QfFinanceLiquidityM;
import com.artfess.cqlt.vo.FaReportRespVo;
import com.artfess.cqlt.vo.ReportReqVo;
import com.artfess.i18n.util.I18nUtil;
import com.artfess.poi.util.CustomHeader;
import com.artfess.poi.util.HeaderNode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.api.client.util.Lists;
import com.google.common.collect.Maps;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 资金--周资金计划填报实际数据详情表 服务实现类
 *
 * @author min.wu
 * @company 阿特菲斯信息技术有限公司
 * @since 2023-03-02
 */
@Service
public class QfFinanceLiquidityDetailManagerImpl extends BaseManagerImpl<QfFinanceLiquidityDetailDao, QfFinanceLiquidityDetail> implements QfFinanceLiquidityDetailManager {

    @Resource
    private QfEnterpriseInfoDao enterpriseInfoDao;

    @Resource
    private QfFinanceLiquidityMDao financeLiquidityMDao;

    @Override
    public List<JSONObject> detailQuery(List<QfFinanceLiquidityDetail> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        String mainId = list.get(0).getMainId();
        QfFinanceLiquidityM mainInfo = financeLiquidityMDao.selectById(mainId);
        if (null == mainInfo) {
            return Lists.newArrayList();
        }
        List<Integer> header = this.baseMapper.getHeader(mainId);

        List<String> enterpriseCodes = this.baseMapper.getEnterpriseCode(mainId);

        Map<String, List<QfFinanceLiquidityDetail>> enterpriseDataMap = list.stream()
                .collect(Collectors.groupingBy(QfFinanceLiquidityDetail::getEnterpriseCode));

        List<JSONObject> detailList = Lists.newArrayList();
        Map<Integer, String> columMap = Maps.newHashMap();
        JSONObject detail = new JSONObject(true);
        detail.put("Period", "Period");
        LocalDate localDate = LocalDate.of(mainInfo.getFillYear(), 1, 1);
        header.forEach(week -> {
            if (week.equals(mainInfo.getFillWeek())) {
                detail.put("Cash Starting Balance", "Cash Starting Balance");
                columMap.put(week, "Cash Starting Balance");
            } else {
                LocalDate startTime = localDate.with(TemporalAdjusters.dayOfWeekInMonth(week - 1, DayOfWeek.SATURDAY));
                LocalDate endTime = localDate.with(TemporalAdjusters.dayOfWeekInMonth(week, DayOfWeek.FRIDAY));
                detail.put(startTime + "\n-" + endTime, startTime + "\n-" + endTime);
                columMap.put(week, startTime + "\n-" + endTime);
            }

        });
        detailList.add(detail);
        for (String code : enterpriseCodes) {
            if (!StringUtil.isNotEmpty(code)) {
                continue;
            }
            if (!enterpriseDataMap.containsKey(code)) {
                continue;
            }
            List<QfFinanceLiquidityDetail> liquidityDetailList = enterpriseDataMap.get(code);
            JSONObject data = new JSONObject(true);
            data.put("Period", code);
            liquidityDetailList.forEach(liquidityDetail -> {
                data.put(columMap.get(liquidityDetail.getFillWeek()), liquidityDetail.getFillData());
                Integer[] dateTypes = new Integer[]{3, 6, 9, 11, 13};
                if (Arrays.asList(dateTypes).contains(liquidityDetail.getDataType())) {
                    data.put("Period", null);
                    if (liquidityDetail.getFillType() == 1) {
                        data.put("Cash Starting Balance", liquidityDetail.getEnterpriseCode());
                    }
                    if (liquidityDetail.getFillType() == 2) {
                        data.put(columMap.get(liquidityDetail.getFillWeek()), liquidityDetail.getFillData());
                    }
                }
            });
            detailList.add(data);
        }
        return detailList;
    }

    @Override
    public void export(HttpServletRequest request, HttpServletResponse response, List<QfFinanceLiquidityDetail> list, String sheetName) throws IOException {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        String mainId = list.get(0).getMainId();
        QfFinanceLiquidityM mainInfo = financeLiquidityMDao.selectById(mainId);
        if (null == mainInfo) {
            return;
        }
        List<Integer> header = this.baseMapper.getHeader(mainId);

        List<String> enterpriseCodes = this.baseMapper.getEnterpriseCode(mainId);
        Map<String, Integer> rowMap = Maps.newHashMap();
        AtomicReference<Integer> row = new AtomicReference<>(0);
        enterpriseCodes.forEach(enterpriseCode -> {
            row.getAndSet(row.get() + 1);
            rowMap.put(enterpriseCode, row.get());
        });
        LocalDate localDate = LocalDate.of(mainInfo.getFillYear(), 1, 1);
        Map<String, Integer> columMap = Maps.newHashMap();
        List<HeaderNode> headerNodeList = Lists.newArrayList();
        AtomicReference<Integer> column = new AtomicReference<>(0);
        header.forEach(week -> {
            column.getAndSet(column.get() + 1);
            HeaderNode headerNode = new HeaderNode();
            headerNode.setRow(0);
            headerNode.setColumn(column.get());
            if (1 == column.get()) {
                headerNode.setHeaderName("Cash Starting Balance");
            } else {
                LocalDate startTime = localDate.with(TemporalAdjusters.dayOfWeekInMonth(week - 1, DayOfWeek.SATURDAY));
                LocalDate endTime = localDate.with(TemporalAdjusters.dayOfWeekInMonth(week, DayOfWeek.FRIDAY));
                headerNode.setHeaderName(startTime + "\n-" + endTime);
            }
            headerNodeList.add(headerNode);
            columMap.put(week + "", headerNode.getColumn());
        });

        HeaderNode headerNode = new HeaderNode();
        headerNode.setRow(0);
        headerNode.setColumn(0);
        headerNode.setHeaderName("Period");

        headerNodeList.add(headerNode);

        list.forEach(detail -> {
            //阈值需特殊处理，阈值当前周无数据，只有预测周有数据
            Integer[] dateTypes = new Integer[]{3, 6, 9, 11, 13};
            HeaderNode node = new HeaderNode();
            node.setRow(rowMap.get(detail.getEnterpriseCode()));
            node.setColumn(columMap.get(detail.getFillWeek() + ""));
            Integer colum = columMap.get(detail.getFillWeek() + "");
            if (1 == colum && Arrays.asList(dateTypes).contains(detail.getDataType())) {
                node.setHeaderName(detail.getEnterpriseCode());
            } else {
                if (null != detail.getFillData()) {
                    node.setHeaderName(detail.getFillData() + "");
                }
            }

            headerNodeList.add(node);

            node = new HeaderNode();
            node.setRow(rowMap.get(detail.getEnterpriseCode()));
            node.setColumn(0);

            if (Arrays.asList(dateTypes).contains(detail.getDataType())) {
                node.setHeaderName(null);
            } else {
                node.setHeaderName(detail.getEnterpriseCode());
            }
            headerNodeList.add(node);

        });

        String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String fileName = String.format(sheetName + "-%s", date);
        CustomHeader.export(headerNodeList, response, fileName, sheetName);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchUpdate(QfFinanceLiquidityM t) {
        Assert.hasText(t.getId(), I18nUtil.getMessage("QfOperationKpiM.reportId", LocaleContextHolder.getLocale()));
        QfFinanceLiquidityM liquidityM = financeLiquidityMDao.selectById(t.getId());
        Assert.notNull(liquidityM, I18nUtil.getMessage("filldata.notExist", LocaleContextHolder.getLocale()));
        Assert.isTrue(!"1".equals(liquidityM.getStatus()),  I18nUtil.getMessage("data_operate", LocaleContextHolder.getLocale()));
        List<QfFinanceLiquidityDetail> list = Lists.newArrayList();
        QueryWrapper<QfEnterpriseInfo> enterpriseInfoQuery = new QueryWrapper<>();
        enterpriseInfoQuery.eq("IS_DELE_", DelStatusEnum.N.getType());
        List<QfEnterpriseInfo> enterpriseInfoList = enterpriseInfoDao.selectList(enterpriseInfoQuery);
        Map<String, QfEnterpriseInfo> enterpriseInfoMap = enterpriseInfoList.stream().collect(Collectors.toMap(item -> item.getCode(), item -> item));
        t.getList().forEach(detail -> {
            detail.setFillDate(liquidityM.getFillDate());
            detail.setMainId(t.getId());
            QueryWrapper<QfFinanceLiquidityDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("main_id_", t.getId());
            queryWrapper.eq("enterprise_code_", detail.getEnterpriseCode());
            QfFinanceLiquidityDetail liquidityDetail = this.baseMapper.selectOne(queryWrapper);
            if (null != liquidityDetail) {
                liquidityDetail.setFillData(detail.getFillData());
                list.add(liquidityDetail);
            } else {
                //处理企业
                if (enterpriseInfoMap.containsKey(detail.getEnterpriseCode())) {
                    QfEnterpriseInfo qfEnterpriseInfo = enterpriseInfoMap.get(detail.getEnterpriseCode());
                    detail.setEnterpriseName(qfEnterpriseInfo.getName());
                    detail.setEnterpriseNameEn(qfEnterpriseInfo.getNameEn());
                }
                list.add(detail);
            }
        });
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        boolean b = this.saveOrUpdateBatch(list);
        return b;
    }

    /**
     * datatype 数据类型(1：资金池公司，2：资金池公司汇总，3：资金池阈值，4：非资金池公司，5：非资金池公司汇总，" +
     *             "6：非资金池阈值，7：萨固密中国区公司，8：萨固密中国区汇总，9：萨固密中国区阈值，10：中国区外汇总，11：中国区外集团阈值，12：集团合计，13：集团阈值)
     * @param t
     * @return
     */
    @Override
    public List<FaReportRespVo> poolPlanData(ReportReqVo t) {
        Assert.notEmpty(t.getPlanWeeks(), "请选择要对比的周范围");
        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(2);
        }

        if (null == t.getWeek() || t.getWeek() <= 0) {
            t.setWeek(DateUtils.getWeek(LocalDate.now()));
        }
        if (null == t.getYear()) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }
        List<FaReportRespVo> planList = this.baseMapper.getPlanData(t);
        FaReportRespVo actualData = this.baseMapper.getActualData(t);
        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(3);
        }
        List<FaReportRespVo> warnList = this.baseMapper.getWarnData(t);
        planList.forEach(plan -> {
            plan.setBudget(plan.getBudget().setScale(2, BigDecimal.ROUND_HALF_UP));
            if (null != actualData) {
                plan.setActual(actualData.getActual().setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            if (StringUtil.isNotEmpty(t.getEnterpriseCode())) {
                return;
            }
            warnList.forEach(warn -> {
                if (warn.getWeek().equals(plan.getWeek())) {
                    plan.setWarnValue(warn.getWarnValue().setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            });

        });

        return planList;
    }
    /**
     * datatype 数据类型(1：资金池公司，2：资金池公司汇总，3：资金池阈值，4：非资金池公司，5：非资金池公司汇总，" +
     *             "6：非资金池阈值，7：萨固密中国区公司，8：萨固密中国区汇总，9：萨固密中国区阈值，10：中国区外汇总，11：中国区外集团阈值，12：集团合计，13：集团阈值)
     * @param t
     * @return
     */
    @Override
    public List<FaReportRespVo> groupPlanData(ReportReqVo t) {
        Assert.notEmpty(t.getPlanWeeks(), "请选择要对比的周范围");
        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(12);
        }

        if (null == t.getWeek() || t.getWeek() <= 0) {
            t.setWeek(DateUtils.getWeek(LocalDate.now()));
        }
        if (null == t.getYear()) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }
        List<FaReportRespVo> planList = this.baseMapper.getPlanData(t);
        FaReportRespVo actualData = this.baseMapper.getActualData(t);
        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(13);
        }
        List<FaReportRespVo> warnList = this.baseMapper.getWarnData(t);

        planList.forEach(plan -> {
            plan.setBudget(plan.getBudget().setScale(2, BigDecimal.ROUND_HALF_UP));
            if (null != actualData) {
                plan.setActual(actualData.getActual().setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            if (StringUtil.isNotEmpty(t.getEnterpriseCode())) {
                return;
            }
            warnList.forEach(warn -> {
                if (warn.getWeek().equals(plan.getWeek())) {
                    plan.setWarnValue(warn.getWarnValue().setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            });
        });

        return planList;
    }

    /**
     * datatype 数据类型(1：资金池公司，2：资金池公司汇总，3：资金池阈值，4：非资金池公司，5：非资金池公司汇总，" +
     *             "6：非资金池阈值，7：萨固密中国区公司，8：萨固密中国区汇总，9：萨固密中国区阈值，10：中国区外汇总，11：中国区外集团阈值，12：集团合计，13：集团阈值)
     * @param t
     * @return
     */
    @Override
    public List<FaReportRespVo> companyPlanData(ReportReqVo t) {
        Assert.notEmpty(t.getPlanWeeks(), "请选择要对比的周范围");

        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(5);
        }
        if (null == t.getWeek() || t.getWeek() <= 0) {
            t.setWeek(DateUtils.getWeek(LocalDate.now()));
        }
        if (null == t.getYear()) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }
        List<FaReportRespVo> planList = this.baseMapper.getPlanData(t);
        FaReportRespVo actualData = this.baseMapper.getActualData(t);
        t.setDataType(6);
        List<FaReportRespVo> warnList = this.baseMapper.getWarnData(t);
        planList.forEach(plan -> {
            plan.setBudget(plan.getBudget().setScale(2, BigDecimal.ROUND_HALF_UP));
            if (null != actualData) {
                plan.setActual(actualData.getActual().setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            if (StringUtil.isNotEmpty(t.getEnterpriseCode())) {
                return;
            }
            warnList.forEach(warn -> {
                if (warn.getWeek().equals(plan.getWeek())) {
                    plan.setWarnValue(warn.getWarnValue().setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            });
        });

        return planList;
    }

    /**
     * datatype 数据类型(1：资金池公司，2：资金池公司汇总，3：资金池阈值，4：非资金池公司，5：非资金池公司汇总，" +
     *             "6：非资金池阈值，7：萨固密中国区公司，8：萨固密中国区汇总，9：萨固密中国区阈值，10：中国区外汇总，11：中国区外集团阈值，12：集团合计，13：集团阈值)
     * @param t
     * @return
     */
    @Override
    public List<FaReportRespVo> chinaCompanyData(ReportReqVo t) {
        Assert.notEmpty(t.getPlanWeeks(), "请选择要对比的周范围");

        if (null == t.getWeek() || t.getWeek() <= 0) {
            t.setWeek(DateUtils.getWeek(LocalDate.now()));
        }
        if (null == t.getYear()) {
            int year = LocalDate.now().getYear();
            t.setYear(year);
        }
        if (!StringUtil.isNotEmpty(t.getEnterpriseCode())) {
            t.setDataType(8);
        }
        List<FaReportRespVo> planList = this.baseMapper.getPlanData(t);
        FaReportRespVo actualData = this.baseMapper.getActualData(t);
        t.setDataType(9);
        List<FaReportRespVo> warnList = this.baseMapper.getWarnData(t);
        planList.forEach(plan -> {
            plan.setBudget(plan.getBudget().setScale(2, BigDecimal.ROUND_HALF_UP));
            if (null != actualData) {
                plan.setActual(actualData.getActual().setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            if (StringUtil.isNotEmpty(t.getEnterpriseCode())) {
                return;
            }
            warnList.forEach(warn -> {
                if (warn.getWeek().equals(plan.getWeek())) {
                    plan.setWarnValue(warn.getWarnValue().setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            });
        });

        return planList;
    }
}
