package cn.palmte.work.service;

import cn.palmte.work.bean.ResponseMsg;
import cn.palmte.work.bean.StatusEnum;
import cn.palmte.work.controller.backend.MonthlySettleController;
import cn.palmte.work.model.*;
import cn.palmte.work.utils.DateKit;
import cn.palmte.work.utils.InterfaceUtil;
import cn.palmte.work.utils.StrKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.jfunc.common.db.QueryHelper;
import top.jfunc.common.db.bean.Page;
import top.jfunc.common.db.utils.Pagination;
import top.jfunc.common.utils.StrUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Yuanping Zhang
 * @date 2022/08/08
 */
@Service
public class MonthlySettleService {
    private static final Logger logger = LoggerFactory.getLogger(MonthlySettleService.class);

    @Autowired
    private MonthlySettleRepository monthlySettleRepository;

    @Autowired
    private MonthlySettleRepositoryCustom monthlySettleRepositoryCustom;

    @Autowired
    private Pagination pagination;

    public Page<MonthlySettle> list(Map<String, String> searchInfo, int pageNumber, int pageSize) {
        QueryHelper queryHelper = getQueryHelper(searchInfo);
        return pagination.paginate(queryHelper.getSql(), MonthlySettle.class,pageNumber,pageSize);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseMsg check(Collection<Map> excelMap, String date) {
        int successCount = 0;
        int errorCount = 0;
        if (date == null || date.length() == 0) {
            return ResponseMsg.buildFailedMsg("请选择导入时间!");
        }
        List<String> errorList = new ArrayList<>();
        List<MonthlySettle> monthlySettleList = new ArrayList<>();
        Set<String> projectNameSet = new HashSet<>();
        for (Map m : excelMap) {
            try {
                final Object o1 = m.get("项目编号");
                if (o1 == null || StrKit.isBlank(o1.toString())) {
                    throw new Exception("项目编号不能为空");
                }

                final Object o2 = m.get("最终业主");
                if (o2 == null || StrKit.isBlank(o2.toString())) {
                    throw new Exception("最终业主不能为空");
                }

                final Object o3 = m.get("合同方");
                if (o3 == null || StrKit.isBlank(o3.toString())) {
                    throw new Exception("合同方不能为空");
                }

                final Object o4 = m.get("项目名称");
                if (o4 == null || StrKit.isBlank(o4.toString())) {
                    throw new Exception("项目名称不能为空");
                }
                String projectName = o4.toString();
                MonthlySettle old = monthlySettleRepository.findByMonthAndProjectName(date, projectName);
                if (old != null) {
                    throw new Exception(o4 + " " + date + "已存在");
                }
                if (projectNameSet.contains(projectName)) {
                    throw new Exception(o4 + " " + date + "重复");
                }

                final Object o5 = m.get("合同金额");
                if (o5 == null || StrKit.isBlank(o5.toString())) {
                    throw new Exception("合同金额不能为空");
                }

                final Object o6 = m.get("累计已收款");
                if (o6 == null || StrKit.isBlank(o6.toString())) {
                    throw new Exception("累计已收款不能为空");
                }

                final Object o7 = m.get("已采购累计付款");
                if (o7 == null || StrKit.isBlank(o7.toString())) {
                    throw new Exception("已采购累计付款不能为空");
                }

                final Object o8 = m.get("已采购累计未付款");
                if (o8 == null || StrKit.isBlank(o8.toString())) {
                    throw new Exception("已采购累计未付款不能为空");
                }

                final Object o9 = m.get("超期垫资金额");
                if (o9 == null || StrKit.isBlank(o9.toString())) {
                    throw new Exception("超期垫资金额不能为空");
                }

                final Object o10 = m.get("销售累计开票金额");
                if (o10 == null || StrKit.isBlank(o10.toString())) {
                    throw new Exception("销售累计开票金额不能为空");
                }

                final Object o11 = m.get("合同编号");
                if (o11 == null || StrKit.isBlank(o11.toString())) {
                    throw new Exception("合同编号不能为空");
                }

                final Object o12 = m.get("项目类型");
                if (o12 == null || StrKit.isBlank(o12.toString())) {
                    throw new Exception("项目类型不能为空");
                }

                final Object o13 = m.get("合同签订时间");
                if (o13 == null || StrKit.isBlank(o13.toString())) {
                    throw new Exception("合同签订时间不能为空");
                }
                if (!o13.toString().matches("\\d{4}-\\d{2}-\\d{2}")) {
                    throw new Exception(o4 + " " + date + "的合同签订时间不符合规范(yyyy-MM-dd)");
                }

                final Object o14 = m.get("销售经理");
                if (o14 == null || StrKit.isBlank(o14.toString())) {
                    throw new Exception("销售经理不能为空");
                }

                final Object o15 = m.get("项目经理");
                if (o15 == null || StrKit.isBlank(o15.toString())) {
                    throw new Exception("项目经理不能为空");
                }

                final Object o16 = m.get("收款节点");
                if (o16 == null || StrKit.isBlank(o16.toString())) {
                    throw new Exception("收款节点不能为空");
                }

                final Object o17 = m.get("收款要求时间");
                if (o17 == null || StrKit.isBlank(o17.toString())) {
                    throw new Exception("收款要求时间不能为空");
                }
                if (!o17.toString().matches("\\d{4}-\\d{2}-\\d{2}")) {
                    throw new Exception(o4 + " " + date + "的收款要求时间不符合规范(yyyy-MM-dd)");
                }

                final Object o18 = m.get("收款金额");
                if (o18 == null || StrKit.isBlank(o18.toString())) {
                    throw new Exception("收款金额不能为空");
                }

                final Object o19 = m.get("实际收款时间");
                if (o19 == null || StrKit.isBlank(o19.toString())) {
                    throw new Exception("实际收款时间不能为空");
                }
                if (!o19.toString().matches("\\d{4}-\\d{2}-\\d{2}")) {
                    throw new Exception(o4 + " " + date + "的实际收款时间不符合规范(yyyy-MM-dd)");
                }

                final Object o20 = m.get("实际收款金额");
                if (o20 == null || StrKit.isBlank(o20.toString())) {
                    throw new Exception("实际收款金额不能为空");
                }

                final Object o21 = m.get("实际欠收金额");
                if (o21 == null || StrKit.isBlank(o21.toString())) {
                    throw new Exception("实际欠收金额不能为空");
                }

                final Object o22 = m.get("超期天数");
                if (o22 == null || StrKit.isBlank(o22.toString())) {
                    throw new Exception("超期天数不能为空");
                }

                final Object o23 = m.get("到货证明");
                if (o23 == null || StrKit.isBlank(o23.toString())) {
                    throw new Exception("到货证明不能为空");
                }

                final Object o24 = m.get("验收报告时间");
                if (o24 == null || StrKit.isBlank(o24.toString())) {
                    throw new Exception("验收报告时间不能为空");
                }
                if (!o24.toString().matches("\\d{4}-\\d{2}-\\d{2}")) {
                    throw new Exception(o4 + " " + date + "的验收报告时间不符合规范(yyyy-MM-dd)");
                }

                final Object o25 = m.get("项目风险预警");
                if (o25 == null || StrKit.isBlank(o25.toString())) {
                    throw new Exception("项目风险预警不能为空");
                }

                final Object o26 = m.get("已计收金额");
                if (o26 == null || StrKit.isBlank(o26.toString())) {
                    throw new Exception("已计收金额不能为空");
                }

                final Object o27 = m.get("未计收金额");
                if (o27 == null || StrKit.isBlank(o27.toString())) {
                    throw new Exception("未计收金额不能为空");
                }

                saveMonthlySettle(m, date, projectName, monthlySettleList);
                projectNameSet.add(projectName);
                successCount++;
            } catch (Exception e) {
                logger.error("", e);
                errorCount++;
                if (!e.getMessage().isEmpty()) {
                    errorList.add(e.getMessage());
                }
            }
        }
        monthlySettleRepository.save(monthlySettleList);
        final ResponseMsg msg = ResponseMsg.buildSuccessMsg(String.format("成功：%d, 失败：%d", successCount, errorCount));
        msg.setData(errorList);
        return msg;
    }

    private void saveMonthlySettle(Map m, String date, String projectName, List<MonthlySettle> monthlySettleList) throws Exception {
        MonthlySettle settle = new MonthlySettle();
        String key;
        Object o1;
        settle.setMonth(date);
        key = "项目编号";
        o1 = m.get(key);
        settle.setProjectNo((String) o1);
        key = "最终业主";
        o1 = m.get(key);
        settle.setOwner((String) o1);
        key = "合同方";
        o1 = m.get(key);
        settle.setContractParty((String) o1);
        key = "项目名称";
        o1 = m.get(key);
        settle.setProjectName((String) o1);
        try {
            key = "合同金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setContractAmount(new BigDecimal((String) o1));
            key = "累计已收款";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setTotalCollect(new BigDecimal((String) o1));
            key = "已采购累计付款";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setTotalPurchasedPaid(new BigDecimal((String) o1));
            key = "已采购累计未付款";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setTotalPurchasedUnpaid(new BigDecimal((String) o1));
            key = "超期垫资金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setTimeOutAmount(new BigDecimal((String) o1));
            key = "销售累计开票金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setTotalBillAmount(new BigDecimal((String) o1));
            key = "实际收款金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setCollectActualAmount(new BigDecimal((String) o1));
            key = "实际欠收金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setUncollectActualAmount(new BigDecimal((String) o1));
            key = "收款金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setCollectAmount(new BigDecimal((String) o1));
            key = "已计收金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setCalColAmount(new BigDecimal((String) o1));
            key = "未计收金额";
            o1 = (m.get(key) == null || "".equals(m.get(key))) ? "0.00" : m.get(key);
            settle.setUncalColAmount(new BigDecimal((String) o1));
        } catch (Exception e) {
            throw new Exception("金额请填入数字格式");
        }
        key = "合同编号";
        o1 = m.get(key);
        settle.setContractNo((String) o1);
        key = "项目类型";
        o1 = m.get(key);
        settle.setProjectType((String) o1);
        try {
            key = "合同签订时间";
            o1 = m.get(key);
            settle.setContractSignTime(DateKit.getDate((String) o1, DateKit.DATE_FORMAT));
            key = "收款要求时间";
            o1 = m.get(key);
            settle.setCollectRequiredTime(DateKit.getDate((String) o1, DateKit.DATE_FORMAT));
            key = "验收报告时间";
            o1 = m.get(key);
            settle.setInspectionReportTime(DateKit.getDate((String) o1, DateKit.DATE_FORMAT));
            key = "实际收款时间";
            o1 = m.get(key);
            settle.setCollectActualTime(DateKit.getDate((String) o1, DateKit.DATE_FORMAT));
        } catch (Exception e) {
            throw new Exception("时间请填入时间格式");
        }

        key = "销售经理";
        o1 = m.get(key);
        settle.setSaleManager((String) o1);
        key = "项目经理";
        o1 = m.get(key);
        settle.setProjectManager((String) o1);
        key = "收款节点";
        o1 = m.get(key);
        settle.setCollectPoint((String) o1);


        key = "超期天数";
        o1 = m.get(key);
        settle.setTimeOutDay((String) o1);
        key = "到货证明";
        o1 = m.get(key);
        settle.setProductCertificate((String) o1);

        key = "项目风险预警";
        o1 = m.get(key);
        settle.setRiskWarning((String) o1);


        monthlySettleList.add(settle);
    }

    public List<MonthlySettle> findOne(String id, String time, String projectName) {
        List<MonthlySettle> list = new ArrayList<>();
        MonthlySettle monthlySettle = findByMonthAndProjectName(time, projectName);
        list.add(monthlySettle);
        return list;
    }

    private QueryHelper getQueryHelper(Map<String, String> searchInfo) {
        QueryHelper queryHelper = new QueryHelper("SELECT s.*, ms.*, FORMAT(s.contract_amount,2) as contractAmountRound, FORMAT(s.total_collect,2) as totalCollectRound, FORMAT(s.total_purchased_paid,2) as totalPurchasedPaidRound, FORMAT(s.total_purchased_unpaid,2) as totalPurchasedUnpaidRound" +
                ", FORMAT(s.time_out_amount,2) as timeOutAmountRound, FORMAT(s.total_bill_amount,2) as totalBillAmountRound, FORMAT(s.collect_amount,2) as collectAmountRound, FORMAT(s.collect_actual_amount,2) as collectActualAmountRound" +
                ", FORMAT(s.uncollect_actual_amount,2) as uncollectActualAmountRound, FORMAT(s.cal_col_amount,2) as calColAmountRound, FORMAT(s.uncal_col_amount,2) as uncalColAmountRound" +
                ", DATE_FORMAT(s.contract_sign_time, '%Y-%m-%d') as contractSignTimeStr, DATE_FORMAT(s.collect_required_time, '%Y-%m-%d') as collectRequiredTimeStr, DATE_FORMAT(s.collect_actual_time, '%Y-%m-%d') as collectActualTimeStr, DATE_FORMAT(s.inspection_report_time, '%Y-%m-%d') as inspectionReportTimeStr ","(select project_name as name, max(ms.month) as time from monthly_settle ms group by ms.project_name)","ms");
        queryHelper.leftJoin("monthly_settle s", "ms.time = s.month and ms.name = s.project_name");

        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("projectNo")),"s.project_no LIKE ?", "%"+searchInfo.get("projectNo")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("name")),"s.project_name LIKE ?", "%"+searchInfo.get("name")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("owner")),"s.owner LIKE ?", "%"+searchInfo.get("owner")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("contractParty")),"s.contract_party LIKE ?", "%"+searchInfo.get("contractParty")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("contractNo")),"s.contract_no LIKE ?", "%"+searchInfo.get("contractNo")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("projectType")),"s.project_type LIKE ?", "%"+searchInfo.get("projectType")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("saleManager")),"s.sale_manager LIKE ?", "%"+searchInfo.get("saleManager")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("projectManager")),"s.project_manager LIKE ?", "%"+searchInfo.get("projectManager")+"%");
        queryHelper.addCondition(StrUtil.isNotEmpty(searchInfo.get("timeOutDay")),"s.time_out_day LIKE ?", "%"+searchInfo.get("timeOutDay")+"%");

        if(StrUtil.isNotEmpty(searchInfo.get("startTime"))){
            String time = searchInfo.get("startTime") + " 00:00:00";
            queryHelper.addCondition("s.collect_actual_time>=?", time);
        }
        if(StrUtil.isNotEmpty(searchInfo.get("endTime"))){
            String time = searchInfo.get("endTime") + " 23:59:59";
            queryHelper.addCondition("s.collect_actual_time<=?", time);
        }
        if(StrUtil.isNotEmpty(searchInfo.get("contractStartTime"))){
            String time = searchInfo.get("contractStartTime") + " 00:00:00";
            queryHelper.addCondition("s.contract_sign_time>=?", time);
        }
        if(StrUtil.isNotEmpty(searchInfo.get("contractEndTime"))){
            String time = searchInfo.get("contractEndTime") + " 23:59:59";
            queryHelper.addCondition("s.contract_sign_time<=?", time);
        }

        queryHelper.addDescOrderProperty("s.id");

        return queryHelper;
    }

    public MonthlySettle findById(int id) {
        QueryHelper queryHelper = new QueryHelper("SELECT s.*, FORMAT(s.contract_amount,2) as contractAmountRound, FORMAT(s.total_collect,2) as totalCollectRound, FORMAT(s.total_purchased_paid,2) as totalPurchasedPaidRound, FORMAT(s.total_purchased_unpaid,2) as totalPurchasedUnpaidRound" +
                ", FORMAT(s.time_out_amount,2) as timeOutAmountRound, FORMAT(s.total_bill_amount,2) as totalBillAmountRound, FORMAT(s.collect_amount,2) as collectAmountRound, FORMAT(s.collect_actual_amount,2) as collectActualAmountRound" +
                ", FORMAT(s.uncollect_actual_amount,2) as uncollectActualAmountRound, FORMAT(s.cal_col_amount,2) as calColAmountRound, FORMAT(s.uncal_col_amount,2) as uncalColAmountRound " +
                ", DATE_FORMAT(s.contract_sign_time, '%Y-%m-%d') as contractSignTimeStr, DATE_FORMAT(s.collect_required_time, '%Y-%m-%d') as collectRequiredTimeStr, DATE_FORMAT(s.collect_actual_time, '%Y-%m-%d') as collectActualTimeStr, DATE_FORMAT(s.inspection_report_time, '%Y-%m-%d') as inspectionReportTimeStr ","monthly_settle","s");
        queryHelper.addCondition("s.id=?", id);
        MonthlySettle first = pagination.findFirst(queryHelper.getSql(), MonthlySettle.class);
        return first;
    }

    public MonthlySettle findByMonthAndProjectName(String month, String projectName) {
        QueryHelper queryHelper = new QueryHelper("SELECT s.*, FORMAT(s.contract_amount,2) as contractAmountRound, FORMAT(s.total_collect,2) as totalCollectRound, FORMAT(s.total_purchased_paid,2) as totalPurchasedPaidRound, FORMAT(s.total_purchased_unpaid,2) as totalPurchasedUnpaidRound" +
                ", FORMAT(s.time_out_amount,2) as timeOutAmountRound, FORMAT(s.total_bill_amount,2) as totalBillAmountRound, FORMAT(s.collect_amount,2) as collectAmountRound, FORMAT(s.collect_actual_amount,2) as collectActualAmountRound" +
                ", FORMAT(s.uncollect_actual_amount,2) as uncollectActualAmountRound, FORMAT(s.cal_col_amount,2) as calColAmountRound, FORMAT(s.uncal_col_amount,2) as uncalColAmountRound " +
                ", DATE_FORMAT(s.contract_sign_time, '%Y-%m-%d') as contractSignTimeStr, DATE_FORMAT(s.collect_required_time, '%Y-%m-%d') as collectRequiredTimeStr, DATE_FORMAT(s.collect_actual_time, '%Y-%m-%d') as collectActualTimeStr, DATE_FORMAT(s.inspection_report_time, '%Y-%m-%d') as inspectionReportTimeStr ","monthly_settle","s");
        queryHelper.addCondition("s.month=?", month);
        queryHelper.addCondition("s.project_name=?", projectName);
        MonthlySettle first = pagination.findFirst(queryHelper.getSql(), MonthlySettle.class);
        return first;
    }
}
