/*
 * Author: wangjian
 * 生成ServiceImpl
 */
package com.tofly.znb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tofly.common.core.util.StringUtil;
import com.tofly.znb.common.constant.BcFylxEnum;
import com.tofly.znb.common.constant.CbjsfsEnum;
import com.tofly.znb.common.constant.JtjslxEnum;
import com.tofly.znb.common.constant.PjztEnum;
import com.tofly.znb.common.exception.FeesErrorCode;
import com.tofly.znb.common.exception.FeesException;
import com.tofly.znb.common.util.ServerUtil;
import com.tofly.znb.common.util.ToolsUtils;
import com.tofly.znb.config.ZnbConfig;
import com.tofly.znb.entity.*;
import com.tofly.znb.entity.Dto.SfJsJg;
import com.tofly.znb.entity.Dto.Sjmx;
import com.tofly.znb.entity.Dto.YycblrDto;
import com.tofly.znb.entity.Vo.SprData1Vo;
import com.tofly.znb.entity.Vo.SprDataVo;
import com.tofly.znb.mapper.YhCbkxxMapper;
import com.tofly.znb.mapper.YyCblrMapper;
import com.tofly.znb.service.*;
import com.tofly.znb.utils.HttpRequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.tofly.znb.mapper.ZnbCbLogMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 智能表抄表同步
 *
 * @author admin
 * @date Fri Aug 01 00:00:00 CST 2025
 */
@Service("znbCbLogService")
@Slf4j
public class ZnbCbLogServiceImpl extends ServiceImpl<ZnbCbLogMapper, ZnbCbLog> implements ZnbCbLogService {

    /**
     * 创建抄表类型
     */

    @Autowired
    private YhCbkxxService yhCbkxxService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private YyCblrService yyCblrService;

    @Autowired
    private ZnbConfig znbConfig;

    @Autowired
    private BmSjService bmSjService;

    @Autowired
    private ZnbCsjsLogService znbCsjsLogService;

    @Autowired
    private YhKhjbxxService yhKhjbxxService;

    @Autowired
    private ZnbZlLogService znbZlLogService;

    @Autowired
    private YyZjzhService zjzhService;


    /**
     * 根据水表雷比尔生成抄表计划
     *
     * @param sblb
     */
    @Transactional
    public String CreateZnbPlanBySblbTask(String sblb) {
        List<YycblrDto> lstCblr = yyCblrService.getCblrByYcb();
        if (CollectionUtil.isEmpty(lstCblr)) {
            throw new FeesException("未检测到抄表计划", FeesErrorCode.BUSINESS_ERROR);
        }

        //Map<String, ZnbCbLog> mapZnbCblog = new HashMap<>();

        String pch = "PCH-" + ToolsUtils.getGuid();
        AtomicInteger count = new AtomicInteger();
        lstCblr.forEach(cblr -> {
            int ret = transactionTemplate.execute(status -> {
                try {
                    ZnbCbLog znbCbLog = new ZnbCbLog();
                    BeanUtils.copyProperties(cblr, znbCbLog);
                    znbCbLog.setId(ToolsUtils.getGuid());
                    znbCbLog.setScds(cblr.getNbzxds());
                    znbCbLog.setBcds(cblr.getNbzxds());
                    znbCbLog.setSccbrq(cblr.getNbzxcbrq());
                    znbCbLog.setJsbz("0");
                    znbCbLog.setClCljg("0");
                    znbCbLog.setClLock("0");
                    znbCbLog.setPch(pch);
                    znbCbLog.setCzsj(new Date());
                    znbCbLog.setCzry("4");
                    znbCbLog.setCbkh(cblr.getCbkh().toString());
                    znbCbLog.setSccj(cblr.getSbsccj());
                    if (this.save(znbCbLog)) {
                        return 1;
                    }
                    return 0;
                    //mapZnbCblog.put(znbCbLog.getId(), znbCbLog);

                } catch (Exception e) {
                    log.error(String.format("用户%s生成抄表计划失败：%s", cblr.getYhbh(), e.getMessage()));
                    return 0;
                }
            });
            count.addAndGet(ret);
        });
        log.info("生成抄表计划数量：" + count.get());
        return pch;
    }


    public void ZnbPlanCb(String pch) throws JsonProcessingException {
        Map<String, ZnbCbLog> lst = this.list(new QueryWrapper<ZnbCbLog>()
                .lambda().eq(ZnbCbLog::getClLock, "0")
                .eq(ZnbCbLog::getClCljg, "0")
                .eq(ZnbCbLog::getJsbz, "0")
                .eq(ZnbCbLog::getSccj, "6")
                .eq(ZnbCbLog::getPch, pch)
        ).stream().collect(Collectors.toMap(ZnbCbLog::getId, Function.identity()));

        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String Date = date.format(formatter);

        //获取指令表
        String token = HttpRequestUtil.GetToken(znbConfig);
        log.info("PRINT-TOKEN：" + token);
        if (StringUtil.isEmpty(token)) {
            throw new FeesException("获取token失败", FeesErrorCode.BUSINESS_ERROR);
        }

        String json = HttpRequestUtil.GETRequest(znbConfig.getApiUrl() + "/authentication/interface/getMeterData?token=" + token, "", "");
        //获取JSON失败
        log.info("------------------");
        log.info(json);
        log.info("------------------");
        if (StringUtil.isEmpty(json)) {
            throw new FeesException("获取JSON失败", FeesErrorCode.BUSINESS_ERROR);
        }
        //   log.info("JSON:" + json);

        ObjectMapper mapper = new ObjectMapper();
        SprData1Vo datas = mapper.readValue(json, SprData1Vo.class);

        // List<SprData1Vo> listData= com.alibaba.fastjson.JSONObject.parseArray(json, SprData1Vo.class);
        Map<String, SprDataVo> sprMapDatas = datas.getData().stream()
                .collect(Collectors.toMap(SprDataVo::getSn, Function.identity()));
        if (CollectionUtil.isEmpty(lst)) {
            throw new FeesException("未检测到抄表计划", FeesErrorCode.BUSINESS_ERROR);
        }
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String getCbPch = "SCCJ-6-" + ToolsUtils.getGuid();
        log.debug("抄表内容开始");

        List<ZnbZlLog> zlLogList = new ArrayList<>();
        AtomicInteger count = new AtomicInteger();
        lst.forEach((id, znbCbLog) -> {
            int ret = transactionTemplate.execute(status -> {
                try {
                    if (StringUtil.isNull(sprMapDatas.get(znbCbLog.getBjbh()))) {
                        return 0;
                    }
                    BigDecimal accFlow = BigDecimal.valueOf(sprMapDatas.get(znbCbLog.getBjbh()).getAccFlow())
                            .setScale(0, RoundingMode.FLOOR);
                    // znbCbLog.setBcds(accFlow.setScale(0, RoundingMode.FLOOR));

                    znbCbLog.setCbZs(accFlow);
                    znbCbLog.setBcds(accFlow);
                    znbCbLog.setCbrybm("4");
                    znbCbLog.setCbryxm("物联网抄表");
                    znbCbLog.setLrrybm("3");
                    znbCbLog.setLrryxm("系统机器");
                    znbCbLog.setLrrq(new Date());
                    znbCbLog.setClClsj(new Date());
                    znbCbLog.setClClry("系统机器");
                    znbCbLog.setCbpl(BigDecimal.valueOf(6));
                    if (accFlow.subtract(znbCbLog.getScds()).compareTo(BigDecimal.ZERO) > 0) {
                        znbCbLog.setCbSl(accFlow.subtract(znbCbLog.getScds()));
                        znbCbLog.setClCljg("1");
                    } else {
                        znbCbLog.setCbSl(BigDecimal.ZERO);
                        znbCbLog.setClCljg("6"); //小于0
                    }
                    znbCbLog.setCbrq(format.parse(sprMapDatas.get(znbCbLog.getBjbh()).readTime));
                    znbCbLog.setJsbz("1");
                    //算费
                    YhKhjbxx khjbxx = yhKhjbxxService.getById(znbCbLog.getYhbh());
                    YhCbkxx cbkxx = yhCbkxxService.getById(znbCbLog.getCbkid());
                    this.updateById(znbCbLog);
                    // 2、水表算费
                    ZnbCsjsLog znbsf = znbsf(znbCbLog, khjbxx, cbkxx);

                    //3.自动扣费,更新资金账户、抄表结算中金额记录
                    BigDecimal ye = zjzhService.znbkf(znbsf, znbCbLog.getYhbh());
                    //4.关阀
                    if (ye.compareTo(BigDecimal.ZERO) < 0) {
                        //下发关阀指令
                        ZnbZlLog znbZlLog = znbZlLogService.addZlLog(znbsf.getBcye(), znbCbLog);
                        zlLogList.add(znbZlLog);
                    }
                    //5.更新智能表指令
                    yyCblrService.updateZnbZxds(cbkxx.getCbkid(), sprMapDatas.get(znbCbLog.getBjbh()).readTime, accFlow);

                    return 1;
                } catch (Exception e) {
                    log.error(String.format("用户%s抄表算费失败：%s", znbCbLog.getYhbh(), e.getMessage()));
                    return 0;
                }
            });
            count.addAndGet(ret);
        });
        znbZlLogService.qdjckgf(zlLogList);
        log.info("抄表算费成功：" + count.get());
    }

//    public void znbPlanInfoUpdate() {
//
//
//    }


    private final static Map<String, BmSj> sjCache = new HashMap<>();
    private final static Map<String, BigDecimal> zbFbsCache = new HashMap<>();

    private void sjCache() {
        sjCache.clear();
        List<BmSj> sjList = bmSjService.list();
        if (CollectionUtil.isEmpty(sjList)) {
            throw new FeesException("系统未配置水价信息", FeesErrorCode.BUSINESS_ERROR);
        }

        sjList.forEach(sj -> sjCache.put(sj.getCode(), sj));
    }

//    private void zbFbsCache() {
//        zbFbsCache.clear();
//        Map<String, BigDecimal> zbFbs = cblrService.getZbFbs();
//        zbFbs.forEach(zbFbsCache::put);
//    }

    /**
     * 智能表算费(同普表算费)
     */
    public ZnbCsjsLog znbsf(ZnbCbLog znbcb, YhKhjbxx yhKhjbxx, YhCbkxx cbkxx) {
        ZnbCsjsLog znbCsjsLog = new ZnbCsjsLog();

        String znbcbId = znbcb.getId();
        znbCsjsLog.setCbLogId(znbcbId);
        znbCsjsLog.setCbjsbz("0");

        sjCache();
        //zbFbsCache();

        BigDecimal ljsl = ObjectUtil.isNull(yhKhjbxx.getJtzqljl()) ? BigDecimal.ZERO : yhKhjbxx.getJtzqljl();

        BigDecimal bcjssl = znbcb.getCbSl();
        SfJsJg sfJsJg = yhsfjs(cbkxx, yhKhjbxx, ljsl, bcjssl);
        jtjsUpdate(sfJsJg, cbkxx, yhKhjbxx);

        BeanUtil.copyProperties(yhKhjbxx, znbCsjsLog, ServerUtil.getNullFields(yhKhjbxx));
        BeanUtils.copyProperties(znbcb, znbCsjsLog, "sl", "id");
        BeanUtils.copyProperties(sfJsJg, znbCsjsLog, ServerUtil.getNullFields(sfJsJg));
        znbCsjsLog.setYsyf(znbcb.getCwrq());
        //判断是否进行过算费
        long count = znbCsjsLogService.lambdaQuery()
                .eq(ZnbCsjsLog::getCbkid, znbCsjsLog.getCbkid())
                .eq(ZnbCsjsLog::getCwrq, znbCsjsLog.getCwrq())
                .eq(ZnbCsjsLog::getYsyf, znbCsjsLog.getYsyf())
                .count();
        if (count == 0) {
            // 附加费
            if (cbkxx.getFjf() != null && cbkxx.getFjf().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal fjf = cbkxx.getFjf();
                znbCsjsLog.setYsfjf(fjf);
                znbCsjsLog.setFjf(fjf);
                znbCsjsLog.setFjfdj(fjf);
            }
            // 消防栓费
            if (cbkxx.getXfsf() != null && cbkxx.getXfsf().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal xfsf = cbkxx.getXfsf();
                znbCsjsLog.setYsqt(xfsf);
            }
            znbCsjsLog.setYsje(znbCsjsLog.getYsje().add(znbCsjsLog.getYsfjf()).add(znbCsjsLog.getYsqt()));
        }


        znbCsjsLog.setSfbc("0");
        znbCsjsLog.setFylx(BcFylxEnum.Zhfy.getValue().toString());
        znbCsjsLog.setFylxmc(BcFylxEnum.Zhfy.getName());
        znbCsjsLog.setCbly("3");

        znbCsjsLog.setChbz(PjztEnum.ZC.getValue());
        znbCsjsLog.setSfrybm("3");
        znbCsjsLog.setSfryxm("系统机器");
        znbCsjsLog.setSflx("1");
        znbCsjsLog.setBjbh(cbkxx.getSbbh());
        znbCsjsLog.setSbsccj(cbkxx.getSbsccj());


        znbCsjsLogService.save(znbCsjsLog);
        return znbCsjsLog;
    }

    private SfJsJg yhsfjs(YhCbkxx cbkxx, YhKhjbxx yhxx, BigDecimal ljsl, BigDecimal bcsl) {
        SfJsJg sfJsJg = new SfJsJg();
        sfJsJg.setRks(yhxx.getRks().toString());
        String cbkid = cbkxx.getCbkid();

        Date now = new Date();
        sfJsJg.setJsrq(now);
        Map<String, BigDecimal> ljslMap = new HashMap<>();
        TreeMap<String, String> slMap = getSlMap(cbkxx, bcsl);

        Map<String, Object> fymxMap = new LinkedHashMap<>();
        slMap.forEach((key, value) -> {
            switch (key) {
                case "L0":
                case "L1": {
                    String sjTag = "";
                    String sjTag2 = "";
                    Map<String, Object> values1 = getValues(value, ljsl, sjTag, sjTag2, cbkxx, yhxx);
                    if (values1.containsKey("ljsl")) {
                        ljslMap.put("ljsljsh", (BigDecimal) values1.get("ljsl"));
                    }
                    fymxMap.putAll(values1);
                    break;
                }
                case "L2": {
                    String sjTag = "sj1";
                    String sjTag2 = "1";
                    Map<String, Object> values1 = getValues(value, ljsl, sjTag, sjTag2, cbkxx, yhxx);
                    if (values1.containsKey("ljsl")) {
                        ljslMap.put("ljsljsh", (BigDecimal) values1.get("ljsl"));
                    }
                    fymxMap.putAll(values1);

                    break;
                }
                case "L3": {
                    String sjTag = "sj2";
                    String sjTag2 = "2";
                    Map<String, Object> values1 = getValues(value, ljsl, sjTag, sjTag2, cbkxx, yhxx);
                    if (values1.containsKey("ljsl")) {
                        ljslMap.put("ljsljsh", (BigDecimal) values1.get("ljsl"));
                    }
                    fymxMap.putAll(values1);
                    break;
                }
            }
        });

        List<BigDecimal> sls = getMxValues(fymxMap, "sl");
        List<BigDecimal> sfs = getMxValues(fymxMap, "sf");
        List<BigDecimal> wsfs = getMxValues(fymxMap, "wsf");
        List<BigDecimal> ljfs = getMxValues(fymxMap, "ljf");
        List<BigDecimal> szyfs = getMxValues(fymxMap, "szyf");
        List<BigDecimal> ecjyfs = getMxValues(fymxMap, "ecjyf");
        List<BigDecimal> fjfs = getMxValues(fymxMap, "fjf");
        List<BigDecimal> xfsfs = getMxValues(fymxMap, "xfsf");


        BigDecimal yssl = sls.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yssf = sfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yswsf = wsfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ysljf = ljfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ysszyf = szyfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ysecjyf = ecjyfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ysfjf = fjfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal ysxfsf = xfsfs.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

        BeanUtil.copyProperties(fymxMap, sfJsJg, ServerUtil.getNullFields(fymxMap));

        //重新赋值
        sfJsJg.setEcjyf(ysecjyf);
        sfJsJg.setSzys(ysszyf);

        CbjsfsEnum cbjsfs = getCbjsfs(slMap, fymxMap);//抄表计算方式（0正常单价，1一表多价，2阶梯,3 一表多价含阶梯；用于判断计价类型，处理显示水价）
        sfJsJg.setCbjsbz(cbjsfs.getValue());
        sfJsJg.setCbjsfs(cbjsfs.getDesc());
        sfJsJg.setJtzqljlJsq(ljsl);
        sfJsJg.setJtzqljl(ljslMap.getOrDefault("ljsljsh", BigDecimal.ZERO));
        sfJsJg.setYssl(yssl);
        sfJsJg.setYssf(yssf);
        sfJsJg.setYsljf(ysljf);//垃圾费按月收取或按量收取
        sfJsJg.setYsszys(ysszyf);//应收水资源费
        sfJsJg.setYswsf(yswsf);
        sfJsJg.setYsecjyf(ysecjyf);
        sfJsJg.setYsfjf(ysfjf);
        sfJsJg.setYsqt(ysxfsf);
        sfJsJg.setYsje(yssf.add(ysljf).add(yswsf).add(ysszyf).add(ysfjf).add(ysxfsf).add(ysecjyf));
        log.info("用户抄表卡:{}; 水价:{};", cbkid, fymxMap);
        return sfJsJg;
    }

    private TreeMap<String, String> getSlMap(YhCbkxx cbkxx, BigDecimal ljsl) {
        TreeMap<String, String> slMap = new TreeMap<>();
        String cbkid = cbkxx.getCbkid();
        String ybdjbz = cbkxx.getYbdjbz();
        if (StringUtils.isBlank(ybdjbz) || "0".equals(ybdjbz)) {
            String sjbm = cbkxx.getSjbm();
            if (StringUtils.isBlank(sjbm)) {
                throw new FeesException("用户水表未配置水价信息", FeesErrorCode.BUSINESS_ERROR);
            }

            slMap.put("L0", String.format("%s_%s", sjbm, ljsl));
            return slMap;
        } else {
            String sjbm1 = cbkxx.getSjbm();
            String sjbm2 = cbkxx.getSjbm1();
            String sjbm3 = cbkxx.getSjbm2();
            BigDecimal slbl1 = BigDecimal.valueOf(cbkxx.getSlbl());
            BigDecimal slbl2 = BigDecimal.valueOf(cbkxx.getSlbl1());
            BigDecimal slbl3 = BigDecimal.valueOf(cbkxx.getSlbl2());
            //定量
            BigDecimal sl1 = null;
            BigDecimal sl2 = null;
            BigDecimal sl3 = null;
            //BigDecimal sl4 = null;
            BigDecimal sysl = ljsl;//剩余水量
            if (slbl1 != null && slbl1.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm1)) {
                if (slbl1.compareTo(BigDecimal.ONE) > 0) {//按量
                    if (sysl.compareTo(slbl1) >= 0) {
                        sl1 = slbl1;
                        sysl = sysl.subtract(slbl1);
                    } else {
                        sl1 = sysl;
                        sysl = BigDecimal.ZERO;
                    }
                    slMap.put("L1", String.format("%s_%s", sjbm1, sl1));
                }

            }

            if (slbl2 != null && slbl2.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm2)) {
                if (slbl2.compareTo(BigDecimal.ONE) > 0) {//按量
                    if (sysl.compareTo(slbl2) >= 0) {
                        sl2 = slbl2;
                        sysl = sysl.subtract(slbl2);
                    } else {
                        sl2 = sysl;
                        sysl = BigDecimal.ZERO;
                    }
                    slMap.put("L2", String.format("%s_%s", sjbm2, sl2));
                }
            }

            if (slbl3 != null && slbl3.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm3)) {
                if (slbl3.compareTo(BigDecimal.ONE) > 0) {//按量
                    if (sysl.compareTo(slbl3) >= 0) {
                        sl3 = slbl3;
                        sysl = sysl.subtract(slbl3);
                    } else {
                        sl3 = sysl;
                        sysl = BigDecimal.ZERO;
                    }
                    slMap.put("L3", String.format("%s_%s", sjbm3, sl3));
                }
            }

            BigDecimal sysl2 = sysl;//按量以外的剩余水量
            if (slbl1 != null && slbl1.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm1)) {
                if (slbl1.compareTo(BigDecimal.ONE) <= 0) {//按比例
                    sl1 = sysl2.multiply(slbl1).setScale(0, RoundingMode.HALF_UP);
                    sysl = sysl.subtract(sl1);
                    slMap.put("L1", String.format("%s_%s", sjbm1, sl1));
                }
            }

            if (slbl2 != null && slbl2.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm2)) {
                if (slbl2.compareTo(BigDecimal.ONE) <= 0) {//按比例
                    //判断水价3是否存在，存在继续进行比例计算，否则按剩余量计算
                    if (slbl3 != null && slbl3.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm3)) {
                        sl2 = sysl2.multiply(slbl2).setScale(0, RoundingMode.HALF_UP);
                        sysl = sysl.subtract(sl2);
                    } else {
                        sl2 = sysl2.subtract(sl1);
                        sysl = BigDecimal.ZERO;
                    }
                    slMap.put("L2", String.format("%s_%s", sjbm2, sl2));
                }
            }

            if (slbl3 != null && slbl3.compareTo(BigDecimal.ZERO) > 0 && StringUtils.isNotEmpty(sjbm3)) {
                if (slbl3.compareTo(BigDecimal.ONE) <= 0 && sysl2.compareTo(BigDecimal.ZERO) > 0) {
                    sl3 = sysl2.subtract(sl1.add(sl2));
                    sysl = BigDecimal.ZERO;
                    slMap.put("L3", String.format("%s_%s", sjbm3, sl3));
                }
            }

            if (slbl1 != null && slbl1.compareTo(BigDecimal.ZERO) == 0 && StringUtils.isNotEmpty(sjbm1)) {
                sl1 = sysl;
                sysl = BigDecimal.ZERO;
                slMap.put("L1", String.format("%s_%s", sjbm1, sl1));

            }

            if (slbl2 != null && slbl2.compareTo(BigDecimal.ZERO) == 0 && StringUtils.isNotEmpty(sjbm2)) {
                sl2 = sysl;
                sysl = BigDecimal.ZERO;
                slMap.put("L2", String.format("%s_%s", sjbm2, sl2));
            }

            if (slbl3 != null && slbl3.compareTo(BigDecimal.ZERO) == 0 && StringUtils.isNotEmpty(sjbm3)) {
                sl3 = sysl;
                sysl = BigDecimal.ZERO;
                slMap.put("L3", String.format("%s_%s", sjbm3, sl3));
            }

            if (sysl.compareTo(BigDecimal.ZERO) > 0) {
                throw new FeesException("一表多价有水量未进入计算", FeesErrorCode.BUSINESS_ERROR);
            }
            return slMap;
        }
    }

    private List<BigDecimal> getMxValues(Map<String, Object> values, String prefix) {
        List<BigDecimal> mxValues = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            String key;
            if (i == 0) {
                key = String.format("%s", prefix);
            } else {
                key = String.format("%s%s", prefix, i);
            }

            if (values.containsKey(key)) {
                mxValues.add((BigDecimal) values.getOrDefault(key, BigDecimal.ZERO));
            }
        }
        return mxValues;
    }

    private Map<String, Object> getValues(String sjsl, BigDecimal ljsl, String sjTag1, String sjTag2, YhCbkxx cbkxx, YhKhjbxx yhxx) {
        String wsfbz = cbkxx.getWsfbz();
        String ljfbz = cbkxx.getLjfbz();

        String[] values = sjsl.split("_");
        String sjbm = values[0];
        BigDecimal sl = new BigDecimal(values[1]);
        // 根据水价信息计算水费
        Sjmx sjmx = sfjs(sl, sjbm, ljsl, yhxx);
        Map<String, Object> map = new LinkedHashMap<>();
        String prefix = "";
        String suffix = sjTag2;
        map.put(String.format("%s%s%s", prefix, "sjbm", suffix), sjbm);
        Sjmx.Jtmx jtmx = sjmx.getJtmx();

        // 水费计算(阶梯/非阶梯)
        if (jtmx != null) {//非阶梯水价
            prefix = sjTag1;
            suffix = sjTag2;
            map.put(String.format("%s%s%s", prefix, "sl", suffix), jtmx.getSl());
            map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx.getSj());
            map.put(String.format("%s%s%s", prefix, "sf", suffix), jtmx.getSf());

            prefix = "";
            suffix = sjTag2;
            map.put(String.format("%s%s%s", prefix, "sl", suffix), jtmx.getSl());
            map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx.getSj());
            map.put(String.format("%s%s%s", prefix, "sf", suffix), jtmx.getSf());
            map.put(String.format("%s%s", "sjjtbz", suffix), "0");
        } else {
            map.put(String.format("%s%s", "sjjtbz", suffix), "1");
            Sjmx.Jtmx jtmx1 = sjmx.getJtmx1();
            BigDecimal zsl = BigDecimal.ZERO;
            BigDecimal zsf = BigDecimal.ZERO;
            if (jtmx1 != null) {
                prefix = "jt1";
                if (StringUtils.isNotBlank(sjTag1)) prefix = sjTag1 + "Jt1";
                suffix = "";
                BigDecimal sl1 = jtmx1.getSl();
                zsl = zsl.add(sl1);
                map.put(String.format("%s%s%s", prefix, "sl", suffix), sl1);
                map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx1.getSj());
                BigDecimal sf = jtmx1.getSf();
                zsf = zsf.add(sf);
                map.put(String.format("%s%s%s", prefix, "sf", suffix), sf);
            }
            Sjmx.Jtmx jtmx2 = sjmx.getJtmx2();
            if (jtmx2 != null) {
                prefix = "jt2";
                if (StringUtils.isNotBlank(sjTag1)) prefix = sjTag1 + "Jt2";
                suffix = "";
                BigDecimal sl1 = jtmx2.getSl();
                zsl = zsl.add(sl1);
                map.put(String.format("%s%s%s", prefix, "sl", suffix), sl1);
                map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx2.getSj());
                BigDecimal sf = jtmx2.getSf();
                zsf = zsf.add(sf);
                map.put(String.format("%s%s%s", prefix, "sf", suffix), sf);
            }
            Sjmx.Jtmx jtmx3 = sjmx.getJtmx3();
            if (jtmx3 != null) {
                prefix = "jt3";
                if (StringUtils.isNotBlank(sjTag1)) prefix = sjTag1 + "Jt3";
                suffix = "";
                BigDecimal sl1 = jtmx3.getSl();
                zsl = zsl.add(sl1);
                map.put(String.format("%s%s%s", prefix, "sl", suffix), sl1);
                map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx3.getSj());
                BigDecimal sf = jtmx3.getSf();
                zsf = zsf.add(sf);
                map.put(String.format("%s%s%s", prefix, "sf", suffix), sf);
            }
            Sjmx.Jtmx jtmx4 = sjmx.getJtmx4();
            if (jtmx4 != null) {
                prefix = "jt4";
                if (StringUtils.isNotBlank(sjTag1)) prefix = sjTag1 + "Jt4";
                suffix = "";
                BigDecimal sl1 = jtmx4.getSl();
                zsl = zsl.add(sl1);
                map.put(String.format("%s%s%s", prefix, "sl", suffix), sl1);
                map.put(String.format("%s%s%s", prefix, "sj", suffix), jtmx4.getSj());
                BigDecimal sf = jtmx4.getSf();
                zsf = zsf.add(sf);
                map.put(String.format("%s%s%s", prefix, "sf", suffix), sf);
            }
            prefix = "";
            suffix = sjTag2;
            map.put(String.format("%s%s%s", prefix, "sl", suffix), zsl);
            map.put(String.format("%s%s%s", prefix, "sf", suffix), zsf);
        }

        //其它费用计算
        BmSj bmSj = sjCache.get(sjbm);
        if (bmSj != null) {
            if (ObjectUtil.isNotNull(bmSj.getJtjslx()) && (bmSj.getJtjslx().equals(JtjslxEnum.YEAR.getValue())
                    || bmSj.getJtjslx().equals(JtjslxEnum.MONTH.getValue()))) {
                map.put("ljsl", ljsl.add(sl));
            }

            prefix = "";
            suffix = sjTag2;
            BigDecimal wsfdj = bmSj.getWsfdj();
            BigDecimal ljfdj = bmSj.getLjfdj();
            BigDecimal szyfdj = bmSj.getSzyfdj();
            BigDecimal ecjyfdj = new BigDecimal("0.1");

            map.put(String.format("%s%s%s", prefix, "wsfdj", suffix), wsfdj);
            map.put(String.format("%s%s%s", prefix, "szysdj", suffix), szyfdj);
            map.put(String.format("%s%s%s", prefix, "ecjyfDj", suffix), ecjyfdj);

            // 二次加压费
            if (cbkxx.getEcjybz() != null && cbkxx.getEcjybz().equals("1")) {
                BigDecimal ecjyf = fyjs(sl, ecjyfdj);
                map.put(String.format("%s%s%s", prefix, "ecjyf", suffix), ecjyf);
            }

//            // 附加费
//            if (cbkxx.getFjf() != null && cbkxx.getFjf().compareTo(BigDecimal.ZERO) > 0) {
//                //附加费只收取一次
//                if (StrUtil.isEmpty(sjTag1) && StrUtil.isEmpty(sjTag2)) {
//                    BigDecimal fjf = cbkxx.getFjf();
//                    map.put(String.format("%s%s%s", prefix, "fjf", suffix), fjf);
//                }
//            }
//
//            // 消防栓费
//            if (cbkxx.getXfsf() != null && BigDecimal.valueOf(cbkxx.getXfsf()).compareTo(BigDecimal.ZERO) > 0) {
//                //消防栓费只收取一次
//                if (StrUtil.isEmpty(sjTag1) && StrUtil.isEmpty(sjTag2)) {
//                    BigDecimal xfsf = BigDecimal.valueOf(cbkxx.getXfsf());
//                    map.put(String.format("%s%s%s", prefix, "xfsf", suffix), xfsf);
//                }
//            }


            // 污水费
            if ("1".equals(wsfbz)) {
                BigDecimal wsf = fyjs(sl, wsfdj);
                map.put(String.format("%s%s%s", prefix, "wsf", suffix), wsf);
            }

            // 垃圾费
            if ("1".equals(ljfbz) && sl.compareTo(BigDecimal.ZERO) > 0) {
                //按量收取垃圾费
                if (cbkxx.getLjffs().equals("1")) {
                    map.put(String.format("%s%s%s", prefix, "ljfdj", suffix), ljfdj);
                    BigDecimal ljf = fyjs(sl, ljfdj);
                    map.put(String.format("%s%s%s", prefix, "ljf", suffix), ljf);
                } else {
                    BigDecimal num = BigDecimal.ONE;
                    //判断总分表或子母表是否存在
                    if (zbFbsCache.size() > 0 && zbFbsCache.containsKey(cbkxx.getCbkid())) {
                        num = zbFbsCache.get(cbkxx.getCbkid());
                        //判断子表数或者分表数是否为0，为零按单户处理
                        if (BigDecimal.ZERO.compareTo(num) == 0) {
                            num = BigDecimal.ONE;
                        }
                    }
                    //按户收取垃圾费是只需要算一次
                    if (StrUtil.isEmpty(sjTag1) && StrUtil.isEmpty(sjTag2)) {
                        map.put(String.format("%s%s%s", prefix, "ljfdj", suffix), cbkxx.getLjfje());
                        BigDecimal ljf = BigDecimal.valueOf(cbkxx.getLjfje()).multiply(num);
                        map.put(String.format("%s%s%s", prefix, "ljf", suffix), ljf);
                    }
                }
            }

            // 水资源费
            if (szyfdj != null && szyfdj.compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal szyf = fyjs(sl, szyfdj);
                map.put(String.format("%s%s%s", prefix, "szyf", suffix), szyf);
            }
        }
        return map;
    }

    private Sjmx sfjs(BigDecimal sl, String sjbm, BigDecimal ljsl, YhKhjbxx yhKhjbxx) {
        BmSj bmSj = sjCache.get(sjbm);
        if (bmSj == null) {
            throw new FeesException("水价编码不存在", FeesErrorCode.BUSINESS_ERROR);
        }

        String jtbz = bmSj.getJtbz();

        if ("1".equals(jtbz)) {
            Long rks = yhKhjbxx.getRks();
            BigDecimal rksqs = BigDecimal.ZERO;//人口数起数
            BigDecimal jtzl = BigDecimal.ZERO;//阶梯增量
            BigDecimal jtZszl = BigDecimal.ZERO;//阶梯止数增量

            BmSj sjdata = bmSjService.getById(sjbm);
            rksqs = sjdata.getJtrkjs();
            jtzl = sjdata.getJtrksl();

            if (rks != null && rks > 0) {
                if (BigDecimal.valueOf(rks).compareTo(rksqs) > 0) {
                    jtZszl = BigDecimal.valueOf(rks).subtract(rksqs).multiply(jtzl);
                }
            }
            Sjmx.Jtmx jtmx1 = null;
            Sjmx.Jtmx jtmx2 = null;
            Sjmx.Jtmx jtmx3 = null;
            Sjmx.Jtmx jtmx4 = null;
            BigDecimal yssl = BigDecimal.ZERO;
            BigDecimal yssf = BigDecimal.ZERO;

            BigDecimal jt1Zs = bmSj.getJt1Zs();
            BigDecimal jt1Sj = bmSj.getJt1Sj();
            BigDecimal sjJtZs = BigDecimal.ZERO;
            if (isEnabled(jt1Zs)) {
                jtmx1 = getJtSf(sl, jt1Zs.add(jtZszl), jt1Sj, sjJtZs, ljsl);
                sjJtZs = jt1Zs;
                yssl = yssl.add(jtmx1.getSl());
                yssf = yssf.add(jtmx1.getSf());
            }

            BigDecimal jt2Zs = bmSj.getJt2Zs();
            BigDecimal jt2Sj = bmSj.getJt2Sj();
            if (isEnabled(jt2Zs) && isEnabled(jt1Zs)) {
                jtmx2 = getJtSf(sl, jt2Zs.add(jtZszl), jt2Sj, sjJtZs.add(jtZszl), ljsl);
                sjJtZs = jt2Zs;
                yssl = yssl.add(jtmx2.getSl());
                yssf = yssf.add(jtmx2.getSf());
            }

            BigDecimal jt3Zs = bmSj.getJt3Zs();
            BigDecimal jt3Sj = bmSj.getJt3Sj();
            if (isEnabled(jt3Zs) && isEnabled(jt2Zs)) {
                jtmx3 = getJtSf(sl, jt3Zs.add(jtZszl), jt3Sj, sjJtZs.add(jtZszl), ljsl);
                sjJtZs = jt3Zs;
                yssl = yssl.add(jtmx3.getSl());
                yssf = yssf.add(jtmx3.getSf());
            }

            BigDecimal jt4Zs = bmSj.getJt4Zs();
            BigDecimal jt4Sj = bmSj.getJt4Sj();
            if (isEnabled(jt4Zs) && isEnabled(jt3Zs)) {
                jtmx4 = getJtSf(sl, jt4Zs.add(jtZszl), jt4Sj, sjJtZs.add(jtZszl), ljsl);
                //sjJtZs = jt4Zs;
                yssl = yssl.add(jtmx4.getSl());
                yssf = yssf.add(jtmx4.getSf());
            }

            if (ljsl.add(sl).compareTo(sjJtZs) > 0) {
                throw new FeesException("用户水量超过" + sjJtZs + ",无法计算", FeesErrorCode.BUSINESS_ERROR);
            }
            return new Sjmx(jtmx1, jtmx2, jtmx3, jtmx4, yssl, yssf);
        } else {
            BigDecimal sj = bmSj.getSj();
            BigDecimal sf = fyjs(sl, sj);
            return new Sjmx(sj, sl, sf);
        }
    }

    private CbjsfsEnum getCbjsfs(TreeMap<String, String> slMap, Map<String, Object> values) {
        CbjsfsEnum cbjsfs = CbjsfsEnum.ZCDJJF;

        if (slMap.containsKey("L0")) {
            String sjjtbz = (String) values.get("sjjtbz");
            if (sjjtbz.equals("0")) {
                cbjsfs = CbjsfsEnum.ZCDJJF;
            } else {
                cbjsfs = CbjsfsEnum.JTJF;
            }
        } else if (slMap.containsKey("L1")) {
            cbjsfs = CbjsfsEnum.YBDJJF;
            for (long i = 0; i <= 2; i++) {
                String Tag = "sjjtbz";
                if (i != 0) {
                    Tag = String.format("sjjtbz%s", i);
                }
                if (values.containsKey(Tag)) {
                    String sjjtbz = (String) values.get(Tag);
                    if (sjjtbz.equals("0")) {
                        cbjsfs = CbjsfsEnum.YBDJJF;
                    } else {
                        cbjsfs = CbjsfsEnum.JTYBDJJF;
                    }
                }
            }
        }
        return cbjsfs;
    }

    private void jtjsUpdate(SfJsJg sfJsJg, YhCbkxx cbkxx, YhKhjbxx yhKhjbxx) {
        if (sfJsJg.getJtzqljl().compareTo(BigDecimal.ZERO) > 0) {
            yhCbkxxService.updateLjsl(cbkxx.getCbkid(), sfJsJg.getJtzqljl());
            yhKhjbxxService.lambdaUpdate().set(YhKhjbxx::getJtzqljl, sfJsJg.getJtzqljl()).eq(YhKhjbxx::getYhbh, yhKhjbxx.getYhbh()).update();
        }
        if (sfJsJg.getYhsl().compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal dbhndljl = sfJsJg.getYhsl().add(yhKhjbxx.getDbhndljl());
            yhKhjbxxService.lambdaUpdate().set(YhKhjbxx::getDbhndljl, dbhndljl).eq(YhKhjbxx::getYhbh, yhKhjbxx.getYhbh()).update();
        }
    }

    private BigDecimal fyjs(BigDecimal sl, BigDecimal sj) {
        if (sj != null) {
            return sl.multiply(sj);
        }

        return BigDecimal.ZERO;
    }

    private boolean isEnabled(BigDecimal jtZs) {
        return jtZs != null && jtZs.compareTo(BigDecimal.ZERO) > 0;
    }

    private Sjmx.Jtmx getJtSf(BigDecimal sl, BigDecimal jtZs, BigDecimal jtSj, BigDecimal sjJtZs, BigDecimal ljsl) {
        //累计水量小于阶梯止数 并且 累计水量+本次水量大于上一阶梯止数
        if (ljsl.compareTo(jtZs) < 0 && ljsl.add(sl).compareTo(sjJtZs) > 0) {
            BigDecimal jtSf;//阶梯水费
            BigDecimal ys = jtZs.subtract(ljsl.add(sl));//求阶梯余数
            BigDecimal jtsl;
            if (ys.compareTo(BigDecimal.ZERO) >= 0) {//阶梯余数大于0则没有超过阶梯止数
                if (ljsl.compareTo(sjJtZs) >= 0) {//累计水量大于上一阶梯止数则无需排除上一阶梯水量直接用sl
                    jtsl = sl;
                } else {//累计水量小于上一阶梯止数则需要排除上一阶梯的sl
                    jtsl = sl.subtract(sjJtZs).add(ljsl);
                }
            } else {//阶梯余数小于0则超过阶梯止数 需要求阶梯剩余水量
                if (ljsl.add(sl).compareTo(jtZs) > 0) {//累计水量加水量大于阶梯止数则直接求阶梯剩余水量
                    if (ljsl.compareTo(sjJtZs) > 0) {//累计水量大于上一阶梯止数则表示当前阶梯有累计水量
                        jtsl = jtZs.subtract(ljsl);
                    } else {
                        jtsl = jtZs.subtract(sjJtZs);
                    }
                } else {//累计水量小于上一阶梯止数则需要sl加上ljsl再减去上一阶梯止数求当前阶梯水量
                    jtsl = sl.subtract(sjJtZs).add(ljsl);
                }
            }
            jtSf = fyjs(jtsl, jtSj);
            return new Sjmx.Jtmx(jtSj, jtsl, jtSf);
        }
        return new Sjmx.Jtmx(jtSj, BigDecimal.ZERO, BigDecimal.ZERO);
    }

}
