package com.tofly.feesapi.common.znj;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tofly.common.core.util.StringUtil;
import com.tofly.feesapi.bmgl.entity.BmYslx;
import com.tofly.feesapi.bmgl.service.BmYslxService;
import com.tofly.feesapi.common.exception.FeesErrorCode;
import com.tofly.feesapi.common.exception.FeesException;
import com.tofly.feesapi.sfgl.entity.YyQfmx;
import com.tofly.feesapi.sfgl.entity.YyWyjjmrq;
import com.tofly.feesapi.sfgl.entity.YyWyjtz;
import com.tofly.feesapi.sfgl.mapper.YyQfmxMapper;
import com.tofly.feesapi.sfgl.service.YyQfmxService;
import com.tofly.feesapi.sfgl.service.YyWyjjmrqService;
import com.tofly.feesapi.sfgl.service.YyWyjtzService;
import com.tofly.feesapi.yhgl.entity.YyZjzh;
import com.tofly.feesapi.yhgl.entity.vo.YyZjzhView;
import com.tofly.feesapi.yhgl.service.IYyZjzhService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 违约金计算
 */
@Service
public class ZnjCal {
    @Autowired
    private YyQfmxMapper yyQfmxMapper;

    @Autowired
    private YyQfmxService yyQfmxService;

    @Autowired
    private BmYslxService bmYslxService;

    @Autowired
    private IYyZjzhService zjzhService;

    @Autowired
    private YyWyjjmrqService yyWyjjmrqService;


    public ZNJResult getZNJ(LocalDate cbrq, String znjJSSS, int days, BigDecimal znjlv, BigDecimal QFYSJE, String qfid, String yhbh) {
        return getZNJ(cbrq, znjJSSS, days, znjlv, QFYSJE, qfid, yhbh, null);
    }

    /**
     * 违约金计算
     *
     * @param cbrq    抄表日期
     * @param znjJSSS 违约金计算方式
     * @param days    天数
     * @param znjlv   违约金利率
     * @param QFYSJE  应收金额
     * @param qfid    欠费ID
     * @return 返回违约金对象
     */
    public ZNJResult getZNJ(LocalDate cbrq, String znjJSSS, int days, BigDecimal znjlv, BigDecimal QFYSJE, String qfid, String yhbh, String sfrq) {
        //判断是否是减免全部违约金用户
        long jmbz = yyQfmxMapper.wyjqbjm(yhbh);
        if (jmbz > 0) {
            return new ZNJResult(BigDecimal.ZERO, 0);
        }
        BigDecimal znj_je = BigDecimal.ZERO;
        LocalDate dt_znjjsksrq = LocalDate.now();

        // 按抄表当月**号以后计算
        if (znjJSSS.equals("01")) {
            if (days <= 0) {
                days = 1;
            }
            try {
                dt_znjjsksrq = LocalDate.of(cbrq.getYear(), cbrq.getMonth(), days);
            } catch (Exception e) {
                //获取当月的最后一天
                dt_znjjsksrq = LocalDate.of(cbrq.getYear(), cbrq.getMonth(), 1)
                        .withDayOfMonth(cbrq.getMonth().length(cbrq.isLeapYear()));
            }
        }
        // 按抄表下月**号以后计算
        else if (znjJSSS.equals("02")) {
            LocalDate localDate = cbrq.plusMonths(1);
            int year = localDate.getYear();
            int month = localDate.getMonthValue();
            if (days <= 0) {
                days = 1;
            }
            try {
                dt_znjjsksrq = LocalDate.of(year, month, days);
            } catch (Exception e) {
                dt_znjjsksrq = LocalDate.of(year, month, 1);
            }
        }
        // 按抄表日期起**天以后计算
        else if (znjJSSS.equals("03")) {
            dt_znjjsksrq = cbrq.plusDays(days);
        }
        //按抄表三个月**号以后计算
        else if (znjJSSS.equals("04")) {
            LocalDate localDate = cbrq.plusMonths(4);
            int year = localDate.getYear();
            int month = localDate.getMonthValue();
            if (days <= 0) {
                days = 1;
            }
            try {
                dt_znjjsksrq = LocalDate.of(year, month, days);
            } catch (Exception e) {
                dt_znjjsksrq = LocalDate.of(year, month, 1);
            }
        }
        LocalDate dt_now = LocalDate.now();
        if (StringUtil.isNotEmpty(sfrq)) {
            dt_now = LocalDate.parse(sfrq, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        //获取减免日期数量
        long jmts = yyWyjjmrqService.lambdaQuery()
                .eq(YyWyjjmrq::getYxbz, "1")
                .between(YyWyjjmrq::getJmrq, dt_znjjsksrq, dt_now)
                .count();
        //计算两个日期相差天数（并加1）
        long znj_ts = ChronoUnit.DAYS.between(dt_znjjsksrq, dt_now) + 1;
        znj_ts = znj_ts - jmts;
        if (znj_ts > 0) {
            znj_je = QFYSJE.multiply(znjlv).multiply(BigDecimal.valueOf(znj_ts));
        } else {
            znj_je = BigDecimal.ZERO;
        }

        // 确保znj_je不小于0
        if (znj_je.compareTo(BigDecimal.ZERO) < 0) {
            znj_je = BigDecimal.ZERO;
        }
        BigDecimal ys_znj = znj_je;
        if (ys_znj.compareTo(BigDecimal.ZERO) > 0) {
            //违约金额不能超过欠费金额的百分之三十
            if (znj_je.compareTo(QFYSJE.multiply(BigDecimal.valueOf(0.3))) > 0) {
                znj_je = QFYSJE.multiply(BigDecimal.valueOf(0.3));
            }
            // 确保znj_je不小于0
            if (znj_je.compareTo(BigDecimal.ZERO) < 0) {
                znj_je = BigDecimal.ZERO;
            }
            //减免违约金
            BigDecimal do_jmje = yyQfmxMapper.selectJmje(qfid);
            if (znj_je.compareTo(do_jmje) >= 0) {
                ys_znj = znj_je.subtract(do_jmje).setScale(2, RoundingMode.HALF_UP);
            } else {
                ys_znj = BigDecimal.ZERO;
            }
        }
        //BigDecimal ys_znj = znj_je.setScale(2, RoundingMode.HALF_UP);
        if (znj_ts < 0) {
            znj_ts = 0;
        }
        return new ZNJResult(ys_znj, znj_ts);
    }

    public void ZnjJsTask() {
        //删除昨日的未支付的违约金减免信息
//        yyWyjtzService.remove(
//                new QueryWrapper<YyWyjtz>().lambda()
//                        .eq(YyWyjtz::getSfbz, "0")
//        );
        List<YyQfmx> yyQfmxList = yyQfmxService.list(
                new QueryWrapper<YyQfmx>().lambda()
                        .ne(YyQfmx::getYsje, 0)
                        .eq(YyQfmx::getSfbz, "0")
                        .eq(YyQfmx::getChbz, "0")
                        .eq(YyQfmx::getSfbc, "0")
                        .and(
                                //排除抄表三个月**号以内的欠费
                                w -> w.apply("sjbm=(" +
                                                "select a.code from bm_sj a " +
                                                "left join bm_yslx b on a.yslx=b.code " +
                                                "where to_date(to_char(add_months(cbrq,4),'yyyy-MM')||to_char(lpad(b.znjday, 2, '0')),'yyyy-MM-dd')<=to_date(to_char(sysdate,'yyyy-MM-dd'),'yyyy-MM-dd') " +
                                                "and sjbm=a.code and b.znjbm='04'" +
                                                ")")
                                        .or()
                                        //排除抄表日期起**天以内的欠费
                                        .apply("sjbm=(" +
                                                "select a.code from bm_sj a " +
                                                "left join bm_yslx b on a.yslx=b.code " +
                                                "where to_date(to_char(cbrq+b.znjday),'yyyy-MM-dd')<=to_date(to_char(sysdate,'yyyy-MM-dd'),'yyyy-MM-dd') " +
                                                "and sjbm=a.code and b.znjbm='03'" +
                                                ")")
                                        .or()
                                        //排除抄表下月**号以内的欠费
                                        .apply("sjbm=(" +
                                                "select a.code from bm_sj a " +
                                                "left join bm_yslx b on a.yslx=b.code " +
                                                "where to_date(to_char(add_months(cbrq,1),'yyyy-MM')||to_char(lpad(b.znjday, 2, '0')),'yyyy-MM-dd')<=to_date(to_char(sysdate,'yyyy-MM-dd'),'yyyy-MM-dd') " +
                                                "and sjbm=a.code and b.znjbm='02'" +
                                                ")")
                                        .or()
                                        //排除抄表当月**号以内的欠费
                                        .apply("sjbm=(" +
                                                "select a.code from bm_sj a " +
                                                "left join bm_yslx b on a.yslx=b.code " +
                                                "where to_date(to_char(cbrq,'yyyy-MM')||to_char(lpad(b.znjday, 2, '0')),'yyyy-MM-dd')<=to_date(to_char(sysdate,'yyyy-MM-dd'),'yyyy-MM-dd') " +
                                                "and sjbm=a.code and b.znjbm='01'" +
                                                ")")
                        )
                        .orderByAsc(YyQfmx::getYhbh)
        );
        Map<String, List<YyQfmx>> map = yyQfmxList.stream().collect(Collectors.groupingBy(YyQfmx::getYhbh));
        map.forEach((k, v) -> {
            YyQfmxZnj(k, v);
        });
    }

    public void YyQfmxZnj(String yhbh, List<YyQfmx> yyQfmxList) {
        if (2 > 1) {
            return;//莱阳没有违约金
        }
        YyQfmxZnj(yhbh, yyQfmxList, null);
    }

    public void YyQfmxZnj(String yhbh, List<YyQfmx> yyQfmxList, String sfrq) {
        if (2 > 1) {
            return;//莱阳没有违约金
        }
        //按财务日期升序排序
        yyQfmxList = yyQfmxList.stream()
                .filter(e -> "0".equals(e.getSfbc()))
                .filter(o -> StrUtil.isNotEmpty(o.getYsyf()))
                .filter(o -> ObjUtil.isNotNull(o.getJsrq()))
                .sorted(Comparator.comparing(YyQfmx::getYsyf).thenComparing(YyQfmx::getJsrq))
                .collect(Collectors.toList());

        //获取用户资金账户
        YyZjzh yyZjzh = zjzhService.getById(yhbh);
        long xh = 1;
        for (YyQfmx yyQfmx : yyQfmxList) {
            String qfid = yyQfmx.getId();
            List<BmYslx> bmYslxs = bmYslxService.lambdaQuery()
                    .inSql(BmYslx::getCode, String.format("select yslx from bm_sj where code='%s'", yyQfmx.getSjbm()))
                    .list();
            if (bmYslxs.size() > 0) {
                BmYslx bmYslx = bmYslxs.get(0);
                // 计算违约金的金额为：应收水费+污水费+水资源费(现只需应收水费)
                //BigDecimal QFYSJE = yyQfmx.getYssf().add(yyQfmx.getYswsf()).add(yyQfmx.getYsszyf());
                BigDecimal QFYSJE = yyQfmx.getYssf();
                if (xh == 1 && StringUtil.isNotNull(yyZjzh) &&
                        yyZjzh.getSyje().compareTo(BigDecimal.ZERO) > 0) {
                    QFYSJE = yyQfmx.getYssf().subtract(yyZjzh.getSyje());
                }

                //日期转换
                LocalDate cbrq = yyQfmx.getCbrq().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                ZNJResult znjResult = getZNJ(cbrq, bmYslx.getZnjbm(), bmYslx.getZnjday(), bmYslx.getZnj(), QFYSJE, qfid, yhbh, sfrq);
                yyQfmxService.update()
                        .set("znjts", znjResult.getZnJTs())
                        .set("znjfl", bmYslx.getZnj())
                        .set("znj", znjResult.getZnJJe())
                        .eq("id", qfid)
                        .update();
                xh++;
            } else {
                throw new FeesException("违约金计算失败！", FeesErrorCode.BUSINESS_ERROR);
            }
        }
    }
}
