package com.tofly.feesapi.bjgl.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.tofly.common.core.util.StringUtil;
import com.tofly.feesapi.bjgl.entity.YhCbkxx;
import com.tofly.feesapi.bjgl.entity.YhCbkxxLog;
import com.tofly.feesapi.bjgl.entity.dto.*;
import com.tofly.feesapi.bjgl.entity.vo.*;
import com.tofly.feesapi.bjgl.mapper.YhCbkxxMapper;
import com.tofly.feesapi.bjgl.service.YhCbkxxLogService;
import com.tofly.feesapi.bjgl.service.YhCbkxxService;
import com.tofly.feesapi.bmgl.entity.BmSj;
import com.tofly.feesapi.bmgl.entity.vo.BmSjSelect;
import com.tofly.feesapi.bmgl.service.BmSjService;
import com.tofly.feesapi.cbgl.entity.YyCblr;
import com.tofly.feesapi.cbgl.service.CjService;
import com.tofly.feesapi.cbgl.service.YyCblrService;
import com.tofly.feesapi.common.constant.JfztEnum;
import com.tofly.feesapi.common.constant.JtjslxEnum;
import com.tofly.feesapi.common.core.dto.Order;
import com.tofly.feesapi.common.core.dto.PageDto;
import com.tofly.feesapi.common.core.vo.PageResult;
import com.tofly.feesapi.common.exception.FeesErrorCode;
import com.tofly.feesapi.common.exception.FeesException;
import com.tofly.feesapi.common.util.GuidGenerator;
import com.tofly.feesapi.common.util.ToolsUtils;
import com.tofly.feesapi.security.util.SecurityUtils;
import com.tofly.feesapi.yhgl.entity.YhKhjbxx;
import com.tofly.feesapi.yhgl.entity.dto.YhKhjbxxInsert;
import com.tofly.feesapi.yhgl.service.YhKhjbxxService;
import com.tofly.feesapi.yhgl.service.YhXzbgLogService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 用户表计信息
 */
@Service("yhCbkxxService")
public class YhCbkxxServiceImpl extends ServiceImpl<YhCbkxxMapper, YhCbkxx> implements YhCbkxxService {
    @Autowired
    private YhCbkxxLogService yhCbkxxLogService;
    @Autowired
    private YyCblrService yyCblrService;
    @Autowired
    private YhKhjbxxService yhKhjbxxService;
    @Autowired
    private BmSjService sjService;
    @Autowired
    private YhXzbgLogService yhXzbgLogService;

    @Autowired
    private ToolsUtils toolsUtils;
    @Autowired(required = false)
    private Map<String, CjService> cjServices;

    @Override
    public List<YhCbkxxSelect> getList(String yhbh) {
        return this.baseMapper.getList(yhbh);
    }

    @Override
    public YhCbkxxView getViewById(String yhbh) {
        YhCbkxxView view = new YhCbkxxView();
        YhCbkxx yhCbkxx = this.getById(yhbh);
        if (yhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
        BeanUtils.copyProperties(yhCbkxx, view);
        return view;
    }

    @Override
    public boolean delByIds(List<String> ids) {
        ids.forEach(id -> delById(id));
        return true;
    }

    @Override
    public boolean delById(String id) {
        YhCbkxx yhCbkxx = this.getById(id);
        if (yhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
        saveLog(null, yhCbkxx, "删除");
        this.removeById(id);
        return true;
    }

    @Override
    public YhCbkxx save(YhKhjbxxInsert insert, String yhbh) {
        YhCbkxx cbkxx = new YhCbkxx();
        BeanUtils.copyProperties(insert.getYhCbkxx(), cbkxx);
        String czrybm = insert.getCzrybm();
        String czryxm = insert.getCzryxm();
        Date czsj = insert.getCzsj();
        cbkxx.setYhbh(yhbh);//用户编号
        cbkxx.setCzrybm(czrybm);
        cbkxx.setCzryxm(czryxm);
        cbkxx.setCzsj(czsj);
        //水表档案
        String cbkh = "1";
        cbkxx.setCbkh(cbkh);//抄表卡号
        String strcbkh = yhbh + cbkh;
        cbkxx.setCbkid(strcbkh);//抄表卡ID
        cbkxx.setJfzt(JfztEnum.正常.toString());//计费状态（1正常，2停用）
        check(cbkxx);
        this.save(cbkxx);
        saveLog(cbkxx, null, "添加");//添加水表档案操作历史
        yyCblrService.save(insert, cbkxx);
        return cbkxx;
    }

    @Override
    public boolean update(YhCbkxxUpdate update) {
        String yhbh = update.getYhbh();
        if (StringUtils.isBlank(yhbh)) throw new FeesException("用户编号不能为空", FeesErrorCode.BUSINESS_ERROR);
        YhCbkxx oldYhCbkxx = this.getById(yhbh);
        if (oldYhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
        YhCbkxx yhCbkxx = new YhCbkxx();
        BeanUtils.copyProperties(oldYhCbkxx, yhCbkxx);
        BeanUtils.copyProperties(update, yhCbkxx);
        check(yhCbkxx);
        yhCbkxx.setCzrybm(String.valueOf(SecurityUtils.getUserId()));
        this.updateById(yhCbkxx);
        saveLog(yhCbkxx, oldYhCbkxx, "修改");
        return true;
    }

    @Override
    public boolean disable(String yhbh) {
        YhCbkxx oldYhCbkxx = getById(yhbh);
        if (oldYhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
        YhCbkxx yhCbkxx = new YhCbkxx();
        BeanUtils.copyProperties(oldYhCbkxx, yhCbkxx);
        yhCbkxx.setJfzt("2");
        this.updateById(yhCbkxx);
        saveLog(yhCbkxx, oldYhCbkxx, "作废");
        return true;
    }

    @Override
    public boolean enable(String yhbh) {
        YhCbkxx yhCbkxx = getById(yhbh);
        if (yhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
        yhCbkxx.setJfzt("1");
        this.updateById(yhCbkxx);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCbxh(YhCbkxxCbxhUpdate update) {
        List<YhCbkxxCbxhYhlist> yhCbkxxCbxhYhlists = update.getList();
        if (yhCbkxxCbxhYhlists == null || yhCbkxxCbxhYhlists.size() == 0) return false;
        Set<String> cbbs = new HashSet<>();
        String crdzhYhbh = update.getCrdzhYhbh();
        //Map<String, YhKhjbxx> yhxxMap = new HashMap<>();
        yhCbkxxCbxhYhlists.forEach(item -> {
            YhKhjbxx yhKhjbxx = yhKhjbxxService.getById(item.getYhbh());
            if (yhKhjbxx == null)
                throw new FeesException(String.format("用户档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            YhCbkxx yhCbkxx = this.getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getYhbh, item.getYhbh())
                    .eq(YhCbkxx::getCbkh, item.getCbkh())
            );
            if (yhCbkxx == null)
                throw new FeesException(String.format("水表档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            String sscbb = yhKhjbxx.getSscbb();
            if (sscbb == null)
                throw new FeesException(String.format("用户档案未分配抄表册:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            cbbs.add(sscbb);
            //yhxxMap.put(yhKhjbxx.getYhbh(), yhKhjbxx);
        });
        if (cbbs.size() > 1) throw new FeesException("用户档案不在同一个抄表本（册）", FeesErrorCode.BUSINESS_ERROR);
        String sscbb = cbbs.stream().findFirst().get();
        //未提供插入位置
        if (StringUtils.isBlank(crdzhYhbh)) {
            //不是cbbyhbhs 因为一个抄表本可能会超过1000条  后续sql in无法满足超过1000条 所以使用sscbb
            int cbxhStart = getMaxCbxh(sscbb);
            for (YhCbkxxCbxhYhlist item : yhCbkxxCbxhYhlists) {
                this.lambdaUpdate()
                        .eq(YhCbkxx::getYhbh, item.getYhbh())
                        .eq(YhCbkxx::getCbkh, item.getCbkh())
                        .set(YhCbkxx::getCbxh, ++cbxhStart).update();
            }
            ;
        } else {
            YhCbkxx insertAfter = this.getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getYhbh, crdzhYhbh)
                    .eq(YhCbkxx::getCbkh, update.getCrdzhCbkh())
            );
            if (insertAfter == null)
                throw new FeesException(String.format("水表档案不存在:%s", crdzhYhbh), FeesErrorCode.BUSINESS_ERROR);
            int cbxh = insertAfter.getCbxh();
            if (cbxh == 0) throw new FeesException("水表档案未分配序号", FeesErrorCode.BUSINESS_ERROR);

            List<String> cbbYhbhs = getCbbYhbhs(sscbb);
            //获取下一位抄表卡序号 判断是否存在
            Integer nextcbxh = getNext(sscbb, cbxh);
            if (nextcbxh != 0) {
                //（先更新后续抄表序号）将后面的所有包括next 更新抄表序号（根据传入list的多少size 增加多少）
                if (cbbYhbhs.stream().count() > 999) {
                    //处理orcl 超过1000条 where in 出错
                    for (Integer i = 0; i < cbbYhbhs.stream().count(); i = i + 900) {
                        this.lambdaUpdate()
                                .ge(YhCbkxx::getCbxh, nextcbxh)
                                .in(YhCbkxx::getYhbh, cbbYhbhs.stream().skip(i).limit(900).collect(Collectors.toList()))
                                .setSql("cbxh = cbxh + " + yhCbkxxCbxhYhlists.size())
                                .update();
                    }
                } else {
                    this.lambdaUpdate()
                            .ge(YhCbkxx::getCbxh, nextcbxh)
                            .in(YhCbkxx::getYhbh, cbbYhbhs)
                            .setSql("cbxh = cbxh + " + yhCbkxxCbxhYhlists.size())
                            .update();
                }
            }
            //前面已经将后续更新完成 这里将空出来的部分填入新的插入抄表序号
            int cbxhStart = cbxh;
            for (YhCbkxxCbxhYhlist item : yhCbkxxCbxhYhlists) {
                this.lambdaUpdate()
                        .eq(YhCbkxx::getYhbh, item.getYhbh())
                        .eq(YhCbkxx::getCbkh, item.getCbkh())
                        .set(YhCbkxx::getCbxh, ++cbxhStart).update();
            }
            ;
        }
        yyCblrService.lambdaUpdate()
                .eq(YyCblr::getSscbb, sscbb)
                .setSql("cbxh=(select a.cbxh from yh_cbkxx a where a.yhbh=yy_cblr.yhbh and a.cbkh=yy_cblr.cbkh)")
                .update();
        return true;
    }

    /**
     * 获取抄表本最大抄表序号
     */
    private int getMaxCbxh(String sscbb) {
        if (sscbb == null || sscbb.isEmpty()) return 0;
        return this.baseMapper.getMaxCbxh(sscbb);
    }

    @Override
    public PageResult<YhCbkxxSelect2> getPage(PageDto pageDto, YhCbkxxFilter filter, List<String> sblbs) {
        List<Order> orders = pageDto.getOrders();
        if (orders.size() > 0) {
            orders = orders.stream().map(item -> {
                if (item.getColumn().equals("yhbh")) {
                    Order order = new Order();
                    order.setColumn("a.yhbh");
                    order.setAsc(item.isAsc());
                    return order;
                }
                return item;
            }).collect(Collectors.toList());
        } else {
            orders.add(new Order("a.yhbh", true));
        }
        pageDto.setOrders(orders);
        PageDto<YhCbkxxSelect2> page = this.baseMapper.getPage(pageDto, filter, sblbs);
        List<BmSjSelect> list = sjService.getList();
        Map<String, BmSjSelect> sjMap = list.stream().collect(Collectors.toMap(BmSjSelect::getCode, e -> e));
        PageResult<YhCbkxxSelect2> pageResult = page.toVo();
        pageResult.getRecords().forEach(e -> {
            String ybdjbz = e.getYbdjbz();
            if (ybdjbz == null) {
                ybdjbz = "0";
                e.setYbdjbz(ybdjbz);
            }
            if ("0".equals(ybdjbz)) {
                if (e.getSjbm() != null) {
                    BmSjSelect bmsj = sjMap.get(e.getSjbm());
                    if (bmsj != null) {
                        e.setSj(bmsj.getHjtsj());
                        e.setSjmc(bmsj.getName());
                    }
                }
            } else {
                if (e.getSjbm() != null) {
                    BmSjSelect bmsj = sjMap.get(e.getSjbm());
                    if (bmsj != null) {
                        e.setSj(bmsj.getHjtsj());
                        e.setSjmc(bmsj.getName());
                    }
                }
                if (e.getSjbm1() != null) {
                    BmSjSelect bmsj = sjMap.get(e.getSjbm1());
                    if (bmsj != null) {
                        e.setSj1(bmsj.getHjtsj());
                        e.setSjmc1(bmsj.getName());
                    }
                }
                if (e.getSjbm2() != null) {
                    BmSjSelect bmsj = sjMap.get(e.getSjbm2());
                    if (bmsj != null) {
                        e.setSj2(bmsj.getHjtsj());
                        e.setSjmc2(bmsj.getName());
                    }
                }
            }

        });
        return pageResult;
    }

    @Override
    public boolean updateSj(YhCbkxxSjUpdate update) {
        List<YhCbkxxSjUpdateItem> yhbhcbkhs = update.getYhbhcbkhs();
        check(update);

        for (YhCbkxxSjUpdateItem yhbhcbkh : yhbhcbkhs) {
            YhCbkxx yhCbkxx = getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getCbkh, yhbhcbkh.getCbkh())
                    .eq(YhCbkxx::getYhbh, yhbhcbkh.getYhbh())
            );
            YhCbkxx oldYhCbkxx = yhCbkxx;
            if (yhCbkxx == null) throw new FeesException("水表档案不存在", FeesErrorCode.BUSINESS_ERROR);
            BeanUtils.copyProperties(update, yhCbkxx);

            updateById(yhCbkxx);

            saveLog(yhCbkxx, oldYhCbkxx, "修改");
            yhXzbgLogService.saveYhxzbgLog(oldYhCbkxx, yhCbkxx);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelCbxh(YhCbkxxCbxhCancel cancel) {
        List<YhCbkxxCbxhYhlist> yhCbkxxCbxhYhlists = cancel.getList();
        if (yhCbkxxCbxhYhlists.size() == 0) {
            return false;
        }
        yhCbkxxCbxhYhlists.forEach(item -> {
            YhKhjbxx yhKhjbxx = yhKhjbxxService.getById(item.getYhbh());
            if (yhKhjbxx == null)
                throw new FeesException(String.format("用户档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            YhCbkxx yhCbkxx = this.getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getYhbh, item.getYhbh())
                    .eq(YhCbkxx::getCbkh, item.getCbkh())
            );
            if (yhCbkxx == null)
                throw new FeesException(String.format("水表档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
        });
        yhCbkxxCbxhYhlists.forEach(e -> {
            this.lambdaUpdate()
                    .eq(YhCbkxx::getYhbh, e.getYhbh())
                    .eq(YhCbkxx::getCbkh, e.getCbkh())
                    .set(YhCbkxx::getCbxh, 0).update();
        });
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) //声明式事务管理
    public boolean sxydCbxh(YhCbkxxCbxhSxyd sxyd) {
        List<YhCbkxxCbxhYhlist> list = sxyd.getList();
        if (list.size() == 0) {
            throw new FeesException("参数错误，用户集合不能为空！", FeesErrorCode.BUSINESS_ERROR);
        }
        if (list.size() > 1000) {
            throw new FeesException("最多只能同时操作1000条数据", FeesErrorCode.BUSINESS_ERROR);
        }
        list.forEach(item -> {
            YhKhjbxx yhKhjbxx = yhKhjbxxService.getById(item.getYhbh());
            if (yhKhjbxx == null)
                throw new FeesException(String.format("用户档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            YhCbkxx yhCbkxx = this.getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getYhbh, item.getYhbh())
                    .eq(YhCbkxx::getCbkh, item.getCbkh())
            );
            if (yhCbkxx == null)
                throw new FeesException(String.format("水表档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
        });
        //合并用户编号与抄表卡号->抄表卡ID
        List<String> stringList = list.stream().map(item -> item.getYhbh() + item.getCbkh()).collect(Collectors.toList());
        List<YyCblr> yyCblrList = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                .in(YyCblr::getCbkid, stringList)
                .select(YyCblr::getSscbb)
                .groupBy(YyCblr::getSscbb)
        );
        //判断是不是同一个抄表册
        if (yyCblrList.size() == 1) {
            List<YyCblr> cbxhlist = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                    .in(YyCblr::getCbkid, stringList)
                    .select(YyCblr::getCbxh)
                    .orderByAsc(YyCblr::getCbxh)
            );
            Boolean ydfx = sxyd.getYdfx();
            //上移下移操作
            if ("1".equals(sxyd.getCzlx())) {
                LambdaUpdateChainWrapper<YyCblr> t = yyCblrService.lambdaUpdate().in(YyCblr::getCbkid, stringList);
                if (ydfx) {
                    String mincbxh = cbxhlist.get(0).getCbxh();
                    t.setSql(String.format("cbxh=cbxh-(1.5+cbxh-%s)", mincbxh));
                } else {
                    String maxcbxh = cbxhlist.get(cbxhlist.size() - 1).getCbxh();
                    t.setSql(String.format("cbxh=cbxh+(1.5+%s-cbxh)", maxcbxh));
                }
                if (t.update()) {
                    String cbbbm = yyCblrList.get(0).getSscbb();
                    yyCblrList = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                            .eq(YyCblr::getSscbb, cbbbm)
                            .gt(YyCblr::getCbxh, 0)
                            .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh)
                    );
                    List<YyCblr> finalYyCblrList = yyCblrList;
                    yyCblrList = IntStream.range(0, finalYyCblrList.size())
                            .mapToObj(index -> {
                                YyCblr item = finalYyCblrList.get(index);
                                item.setCbxh(String.valueOf(index + 1));
                                return item;
                            })
                            .collect(Collectors.toList());
                    List<List<YyCblr>> listList = Lists.partition(yyCblrList, 1000);
                    for (List<YyCblr> e : listList) {
                        yyCblrService.updateBatchById(e);
                        this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                    }
                }
            } else if ("2".equals(sxyd.getCzlx())) {
                String cbbbm = yyCblrList.get(0).getSscbb();
                if (ydfx) {  //置顶操作
                    List<YyCblr> czyyCblrList = yyCblrService.lambdaQuery()
                            .in(YyCblr::getCbkid, stringList)
                            .list();
                    //先进行置顶
                    yyCblrList = IntStream.range(0, czyyCblrList.size())
                            .mapToObj(index -> {
                                YyCblr item = czyyCblrList.get(index);
                                item.setCbxh(String.valueOf(index + 1));
                                return item;
                            })
                            .collect(Collectors.toList());
                    yyCblrService.updateBatchById(yyCblrList);
                    //查询出除置顶用户外全部数据
                    List<YyCblr> oldYyCblrList = yyCblrService.lambdaQuery()
                            .eq(YyCblr::getSscbb, cbbbm)
                            .gt(YyCblr::getCbxh, 0)
                            .notIn(YyCblr::getCbkid, stringList)
                            .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh)
                            .list();
                    //从置顶用户数开始更新抄表序号
                    yyCblrList = IntStream.range(0, oldYyCblrList.size())
                            .mapToObj(index -> {
                                YyCblr item = oldYyCblrList.get(index);
                                item.setCbxh(String.valueOf(index + 1 + list.size()));
                                return item;
                            })
                            .collect(Collectors.toList());
                    List<List<YyCblr>> listList = Lists.partition(yyCblrList, 1000);
                    for (List<YyCblr> e : listList) {
                        yyCblrService.updateBatchById(e);
                        this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                    }
                } else {//置底操作
                    //查询出除置底用户外全部数据
                    List<YyCblr> oldYyCblrList = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                            .eq(YyCblr::getSscbb, cbbbm)
                            .gt(YyCblr::getCbxh, 0)
                            .notIn(YyCblr::getCbkid, stringList)
                            .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh));
                    //先进行除置底用户外的抄表序号更新
                    yyCblrList = IntStream.range(0, oldYyCblrList.size())
                            .mapToObj(index -> {
                                YyCblr item = oldYyCblrList.get(index);
                                item.setCbxh(String.valueOf(index + 1));
                                return item;
                            })
                            .collect(Collectors.toList());
                    List<List<YyCblr>> listList = Lists.partition(yyCblrList, 1000);
                    for (List<YyCblr> e : listList) {
                        yyCblrService.updateBatchById(e);
                        this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                    }
                    //从已重新排序的用户数开始更新抄表序号（进行置底操作）
                    List<YyCblr> czyyCblrList = yyCblrService.lambdaQuery()
                            .in(YyCblr::getCbkid, stringList)
                            .list();
                    yyCblrList = IntStream.range(0, czyyCblrList.size())
                            .mapToObj(index -> {
                                YyCblr item = czyyCblrList.get(index);
                                item.setCbxh(String.valueOf(index + 1 + oldYyCblrList.size()));
                                return item;
                            })
                            .collect(Collectors.toList());
                    yyCblrService.updateBatchById(yyCblrList);
                }
            } else {
                throw new FeesException("操作类型错误!", FeesErrorCode.BUSINESS_ERROR);
            }
        } else {
            throw new FeesException("用户所属抄表册有误!", FeesErrorCode.BUSINESS_ERROR);
        }
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class) //声明式事务管理
    public boolean zxtzCbxh(YhCbkxxCbxhZytz zytz) {
        if (zytz.getCbxhnum() < 1) {
            throw new FeesException("参数错误，抄表位置必须大于0！", FeesErrorCode.BUSINESS_ERROR);
        }
        List<YhCbkxxCbxhYhlist> list = zytz.getList();
        if (list.size() == 0) {
            throw new FeesException("参数错误，用户集合不能为空！", FeesErrorCode.BUSINESS_ERROR);
        }
        if (list.size() > 1000) {
            throw new FeesException("最多只能同时操作1000条数据", FeesErrorCode.BUSINESS_ERROR);
        }
        list.forEach(item -> {
            YhKhjbxx yhKhjbxx = yhKhjbxxService.getById(item.getYhbh());
            if (yhKhjbxx == null)
                throw new FeesException(String.format("用户档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
            YhCbkxx yhCbkxx = this.getOne(new QueryWrapper<YhCbkxx>().lambda()
                    .eq(YhCbkxx::getYhbh, item.getYhbh())
                    .eq(YhCbkxx::getCbkh, item.getCbkh())
            );
            if (yhCbkxx == null)
                throw new FeesException(String.format("水表档案不存在:%s", item.getYhbh()), FeesErrorCode.BUSINESS_ERROR);
        });
        //合并用户编号与抄表卡号->抄表卡ID（这样处理是防止一户多表）
        List<String> stringList = list.stream().map(item -> item.getYhbh() + item.getCbkh()).collect(Collectors.toList());
        List<YyCblr> yyCblrList = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                .in(YyCblr::getCbkid, stringList)
                .select(YyCblr::getSscbb)
                .groupBy(YyCblr::getSscbb)
        );
        //判断是不是同一个抄表册
        if (yyCblrList.size() == 1) {
            String cbbbm1 = zytz.getCbbbm();
            String cbbbm2 = yyCblrList.get(0).getSscbb();
            String upcbbbm = cbbbm2;
            if (StringUtil.isNotEmpty(cbbbm1)) {
                upcbbbm = cbbbm1;
            }
            //原有抄表册进行重新排序
            List<YyCblr> oldYyCblrs = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                    .eq(YyCblr::getSscbb, cbbbm2)
                    .gt(YyCblr::getCbxh, 0)
                    .notIn(YyCblr::getCbkid, stringList)
                    .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh));
            yyCblrList = IntStream.range(0, oldYyCblrs.size())
                    .mapToObj(index -> {
                        YyCblr item = oldYyCblrs.get(index);
                        item.setCbxh(String.valueOf(index + 1));
                        return item;
                    })
                    .collect(Collectors.toList());
            List<List<YyCblr>> oldlistList = Lists.partition(yyCblrList, 1000);
            for (List<YyCblr> e : oldlistList) {
                yyCblrService.updateBatchById(e);
                this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
            }

            //判断是否跳转到序号到1
            if (zytz.getCbxhnum() == 1) {
                List<YyCblr> czyyCblrList = yyCblrService.lambdaQuery()
                        .in(YyCblr::getCbkid, stringList)
                        .list();
                yyCblrList = IntStream.range(0, czyyCblrList.size())
                        .mapToObj(index -> {
                            YyCblr item = czyyCblrList.get(index);
                            item.setCbxh(String.valueOf(index + 1));
                            return item;
                        })
                        .collect(Collectors.toList());
                yyCblrService.updateBatchById(yyCblrList);
                this.baseMapper.updatecbxh(yyCblrList.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                //如果是转移则修改用户所属抄表册
                if (StringUtil.isNotEmpty(cbbbm1)) {
                    yhKhjbxxService.lambdaUpdate()
                            .set(YhKhjbxx::getSscbb, upcbbbm)
                            .in(YhKhjbxx::getYhbh, czyyCblrList.stream().map(YyCblr::getYhbh).collect(Collectors.toList()))
                            .update();
                }
                //查询出除置顶用户外全部数据
                List<YyCblr> oldYyCblrList = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                        .eq(YyCblr::getSscbb, upcbbbm)
                        .gt(YyCblr::getCbxh, 0)
                        .notIn(YyCblr::getCbkid, stringList)
                        .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh));
                //从置顶用户数开始更新抄表序号
                yyCblrList = IntStream.range(0, oldYyCblrList.size())
                        .mapToObj(index -> {
                            YyCblr item = oldYyCblrList.get(index);
                            item.setCbxh(String.valueOf(index + 1 + list.size()));
                            return item;
                        })
                        .collect(Collectors.toList());
                List<List<YyCblr>> listList = Lists.partition(yyCblrList, 1000);
                for (List<YyCblr> e : listList) {
                    yyCblrService.updateBatchById(e);
                    this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                }
            } else {
                long count = yyCblrService.count(new QueryWrapper<YyCblr>().lambda()
                        .eq(YyCblr::getSscbb, upcbbbm)
                        .gt(YyCblr::getCbxh, 0));
                //抄表位置小于抄表记录,则为插入
                Integer insertIndex = zytz.getCbxhnum();
                //先对插入记录进行排序
                List<YyCblr> czyyCblrList = yyCblrService.lambdaQuery()
                        .in(YyCblr::getCbkid, stringList)
                        .list();
                yyCblrList = IntStream.range(0, czyyCblrList.size())
                        .mapToObj(index -> {
                            YyCblr item = czyyCblrList.get(index);
                            item.setCbxh(String.valueOf(index + insertIndex));
                            return item;
                        })
                        .collect(Collectors.toList());
                yyCblrService.updateBatchById(yyCblrList);
                //如果是转移则修改用户所属抄表册
                if (StringUtil.isNotEmpty(cbbbm1)) {
                    yhKhjbxxService.lambdaUpdate()
                            .set(YhKhjbxx::getSscbb, upcbbbm)
                            .in(YhKhjbxx::getYhbh, czyyCblrList.stream().map(YyCblr::getYhbh).collect(Collectors.toList()))
                            .update();
                }
                //更新插入之后抄表序号
                if (zytz.getCbxhnum() <= count) {
                    yyCblrService.lambdaUpdate()
                            .setSql("cbxh = cbxh +" + list.size())
                            .eq(YyCblr::getSscbb, upcbbbm)
                            .ge(YyCblr::getCbxh, insertIndex)
                            .notIn(YyCblr::getCbkid, stringList)
                            .update();
                }
                //获取抄表本的全部抄表序号
                List<YyCblr> upYyCblrs = yyCblrService.list(new QueryWrapper<YyCblr>().lambda()
                        .eq(YyCblr::getSscbb, upcbbbm)
                        .orderByAsc(YyCblr::getCbxh, YyCblr::getYhbh, YyCblr::getCbkh));
                //对抄表序号进行重新排序
                yyCblrList = IntStream.range(0, upYyCblrs.size())
                        .mapToObj(index -> {
                            YyCblr item = upYyCblrs.get(index);
                            item.setCbxh(String.valueOf(index + 1));
                            return item;
                        })
                        .collect(Collectors.toList());
                List<List<YyCblr>> listList = Lists.partition(yyCblrList, 1000);
                for (List<YyCblr> e : listList) {
                    yyCblrService.updateBatchById(e);
                    this.baseMapper.updatecbxh(e.stream().map(YyCblr::getCbkid).collect(Collectors.toList()));
                }
            }
        } else {
            throw new FeesException("用户所属抄表册有误!", FeesErrorCode.BUSINESS_ERROR);
        }
        return true;
    }

    @Override
    public void updateSblc(String yhbh, String sblcbm) {
        this.lambdaUpdate()
                .eq(YhCbkxx::getYhbh, yhbh)
                .set(YhCbkxx::getSblc, sblcbm).update();
    }

    @Override
    public List<YhCbkxx> getListByAfterCbkid(String sblb, String sbsccj, String afterCbkid, int limit) {
        PageDto<YhCbkxx> page1 = new PageDto<>();
        page1.setSize(limit);
        page1.setCurrent(1);
        PageDto<YhCbkxx> page = this.page(page1, Wrappers.lambdaQuery(YhCbkxx.class)
                .eq(sblb != null, YhCbkxx::getSblb, sblb)
                .eq(sbsccj != null, YhCbkxx::getSbsccj, sbsccj)
                .gt(afterCbkid != null, YhCbkxx::getCbkid, afterCbkid)
                .orderByAsc(YhCbkxx::getCbkid));
        return page.getRecords();
    }

    @Override
    public long count(String sblb, String sbsccj) {
        return this.list(Wrappers.lambdaQuery(YhCbkxx.class)
                .select(YhCbkxx::getCbkid)
                .eq(sblb != null, YhCbkxx::getSblb, sblb)
                .eq(sbsccj != null, YhCbkxx::getSbsccj, sbsccj)
                .last("for update")).stream().count();
    }

    @Override
    public void lockTable() {
        this.baseMapper.lockTable();
    }

    @Override
    public void updateLjsl(String cbkid, BigDecimal ljsl) {
        if (cbkid == null) return;
        this.lambdaUpdate()
                .set(YhCbkxx::getLjsl, ljsl)
                .eq(YhCbkxx::getCbkid, cbkid)
                .update();
    }

    @Override
    public void updateSyje(String cbkid, BigDecimal syje) {
        if (cbkid == null) return;
        this.lambdaUpdate()
                .set(YhCbkxx::getSyje, syje)
                .eq(YhCbkxx::getCbkid, cbkid)
                .update();
    }

    @Override
    public void znbSync() {
        if (cjServices == null || cjServices.isEmpty()) return;
        cjServices.forEach((serviceName, cjService) -> {
            if (Thread.interrupted()) return;
            String[] nameParts = serviceName.split("#");
            if (nameParts.length < 2) {
                log.error("厂家服务名称错误");
                return;
            }
            String sbsccj = nameParts[1];
            List<YhCbkxxSync> cbkxxSyncs = this.getBySbsccj(sbsccj);
            cjService.syncMeters(cbkxxSyncs);
        });
    }

    @Override
    public List<YhCbkxxSync> getBySbsccj(String sbsccj) {
        if (sbsccj == null) return new ArrayList<>();
        return this.baseMapper.getBySbsccj(sbsccj);
    }

    @Override
    public List<YhCbkxxSelectSbfl> sblbtj(String ysxz, String sbkj) {
        return this.baseMapper.sblbtj(ysxz, sbkj);
    }

    /**
     * 获取用户编号所在抄表本（册）的所有用户编号
     */
    private List<String> getCbbYhbhs(String sscbb) {

        if (sscbb == null) return new ArrayList<>();
        List<YhKhjbxx> list = yhKhjbxxService.lambdaQuery()
                .eq(YhKhjbxx::getSscbb, sscbb)
                .select(YhKhjbxx::getYhbh)
                .list();
        return list.stream().map(YhKhjbxx::getYhbh).collect(Collectors.toList());//抄表本（册）用户编号
    }

    /**
     * 下一位抄表序号是否存在
     */
    private Integer getNext(String sscbb, Integer cbxh) {
        if (sscbb == null || sscbb.isEmpty()) return 0;
        return this.baseMapper.getNextCbxh(sscbb, cbxh + 1);
    }


    private void check(YhCbkxx cbkxx) {
        checkJbcs(cbkxx);

        String ybdjbz = cbkxx.getYbdjbz();
        String wsfbz = cbkxx.getWsfbz();
        String sjbm1 = cbkxx.getSjbm1();
        BigDecimal slbl1 = cbkxx.getSlbl1();
        String sjbm2 = cbkxx.getSjbm2();
        BigDecimal slbl2 = cbkxx.getSlbl2();
        String sjbm3 = cbkxx.getSjbm3();
        BigDecimal slbl3 = cbkxx.getSlbl3();
        String sjbm = cbkxx.getSjbm();
        BigDecimal slbl = cbkxx.getSlbl();
        checkFycs(ybdjbz, wsfbz, sjbm, slbl, sjbm1, slbl1, sjbm2, slbl2);
    }

    /**
     * 检查基本参数
     *
     * @param cbkxx
     */
    private void checkJbcs(YhCbkxx cbkxx) {
        if (StringUtils.isEmpty(cbkxx.getSbbh())) {
            throw new FeesException("水表编号不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtils.isEmpty(cbkxx.getSblb())) {
            throw new FeesException("水表类别不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtils.isEmpty(cbkxx.getSbsccj())) {
            throw new FeesException("水表厂家不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtils.isEmpty(cbkxx.getSbxh())) {
            throw new FeesException("水表型号不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtils.isEmpty(cbkxx.getSbkj())) {
            throw new FeesException("水表口径不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
    }

    /**
     * 检查费用参数
     */
    private void checkFycs(String ybdjbz, String wsfbz, String sjbm, BigDecimal slbl, String sjbm1, BigDecimal slbl1, String sjbm2, BigDecimal slbl2) {

        List<String> bzValues = Arrays.asList("1", "0");
        if (ybdjbz != null && !bzValues.contains(ybdjbz))
            throw new FeesException("是否一表多价标志无效", FeesErrorCode.BUSINESS_ERROR);
        if (wsfbz != null && !bzValues.contains(wsfbz))
            throw new FeesException("污水费标志无效", FeesErrorCode.BUSINESS_ERROR);
        if ("1".equals(ybdjbz)) {
            if (StringUtils.isEmpty(sjbm)) throw new FeesException("水价编码不能为空", FeesErrorCode.BUSINESS_ERROR);
//            if (StringUtils.isEmpty(sjbm1)) throw new FeesException("水价1编码不能为空", FeesErrorCode.BUSINESS_ERROR);
            if (StringUtils.isEmpty(sjbm1)) throw new FeesException("水价1编码不能为空", FeesErrorCode.BUSINESS_ERROR);

            BigDecimal slblCnt = BigDecimal.ZERO;//不大于1的比例
            List<BmSj> bmSjs = new ArrayList<>();

            //=================水量比例===================
            BmSj bmSj = sjService.getById(sjbm);
            if (bmSj == null) {
                throw new FeesException("水价1编码不存在", FeesErrorCode.BUSINESS_ERROR);
            }

            if (slbl == null || slbl.compareTo(BigDecimal.ZERO) < 0) {
                throw new FeesException("水量比例1不能小于0", FeesErrorCode.BUSINESS_ERROR);
            }
            bmSjs.add(bmSj);
            if (slbl.compareTo(BigDecimal.ONE) <= 0) {
                slblCnt = slblCnt.add(slbl);
            }

            //=================水量比例1完成===================


            //=================水量比例2===================
            BmSj bmSj1 = sjService.getById(sjbm1);

            if (bmSj1 == null) {
                throw new FeesException("水价2编码不存在", FeesErrorCode.BUSINESS_ERROR);
            }

            if (slbl1 == null || slbl1.compareTo(BigDecimal.ZERO) < 0) {
                throw new FeesException("水量比例2不能小于0", FeesErrorCode.BUSINESS_ERROR);
            }

            bmSjs.add(bmSj1);
            if (slbl1.compareTo(BigDecimal.ONE) <= 0) {
                slblCnt = slblCnt.add(slbl1);
            }

            //=================水量比例2===================


            //=================水量比例3===================
            if (StringUtils.isNotEmpty(sjbm2)) {
                BmSj bmSj2 = sjService.getById(sjbm2);
                if (bmSj2 == null) {
                    throw new FeesException("水价3编码不存在", FeesErrorCode.BUSINESS_ERROR);
                }

                if (slbl2 == null || slbl2.compareTo(BigDecimal.ZERO) < 0) {
                    throw new FeesException("水量比例3不能小于0", FeesErrorCode.BUSINESS_ERROR);
                }

                bmSjs.add(bmSj2);
                if (slbl2.compareTo(BigDecimal.ONE) <= 0) {
                    slblCnt = slblCnt.add(slbl2);
                }
            }

            if (slblCnt.compareTo(BigDecimal.ONE) != 0)
                throw new FeesException("水量比例之和不等于1", FeesErrorCode.BUSINESS_ERROR);

            long count = bmSjs.stream().filter(e -> e.getJtjslx() == JtjslxEnum.年阶梯).count();
            if (count > 1) throw new FeesException("一表多价最多支持一种年阶梯水价", FeesErrorCode.BUSINESS_ERROR);
        } else {

            if (StringUtils.isEmpty(sjbm)) throw new FeesException("水价编码不能为空", FeesErrorCode.BUSINESS_ERROR);
            BmSj bmSj = sjService.getById(sjbm);
            if (bmSj == null) throw new FeesException("水价编码不存在", FeesErrorCode.BUSINESS_ERROR);
        }
    }

    private void check(YhCbkxxSjUpdate sjUpdate) {
        List<YhCbkxxSjUpdateItem> yhbhcbkhs = sjUpdate.getYhbhcbkhs();
        if (yhbhcbkhs == null || yhbhcbkhs.size() == 0) {
            throw new FeesException("用户编号不能为空", FeesErrorCode.BUSINESS_ERROR);
        }

        String ybdjbz = sjUpdate.getYbdjbz();
        String wsfbz = sjUpdate.getWsfbz();
        String sjbm1 = sjUpdate.getSjbm1();
        BigDecimal slbl1 = sjUpdate.getSlbl1();
        String sjbm2 = sjUpdate.getSjbm2();
        BigDecimal slbl2 = sjUpdate.getSlbl2();
        String sjbm3 = sjUpdate.getSjbm3();
        BigDecimal slbl3 = sjUpdate.getSlbl3();
        String sjbm = sjUpdate.getSjbm();
        BigDecimal slbl = sjUpdate.getSlbl();
        checkFycs(ybdjbz, wsfbz, sjbm, slbl, sjbm1, slbl1, sjbm2, slbl2);
    }


    /**
     * 水表档案操作日志记录
     *
     * @param cbkxx
     * @param oldCbkxx
     * @param logCzlx
     */
    @Override
    public void saveLog(YhCbkxx cbkxx, YhCbkxx oldCbkxx, String logCzlx) {
        if (cbkxx.equals(oldCbkxx)) {
            return;
        }
        String logCzrybm = "";
        String logCzryxm = "";
        if ("用户性质变更".equals(logCzlx)) {
            logCzrybm = "3";
            logCzryxm = "系统机器";
            logCzlx = "修改";
        } else {
            logCzrybm = String.valueOf(SecurityUtils.getUserId());
            logCzryxm = SecurityUtils.getUser().getRealName();
        }
        Date logCzsj = new Date();
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String logLsh = dateFormat.format(logCzsj);
        String log_bz = "";
        if (oldCbkxx != null) {
//            YhCbkxxLog before = new YhCbkxxLog();
//            BeanUtils.copyProperties(oldCbkxx, before);
//            before.setLogLsh(logLsh);
//            before.setCzsj(logCzsj);
//            before.setLogCzryxm(logCzryxm);
//            before.setLogCzrybm(logCzrybm);
//            before.setLogCzsj(logCzsj);
//            before.setLogId(GuidGenerator.getGuid());
//            before.setLogCzlx(logCzlx);
//            before.setLogCllx(String.format("%s前", logCzlx));
//            yhCbkxxLogService.save(before);
            log_bz = toolsUtils.compareFieldDiffToJson(oldCbkxx, cbkxx);
        }

        if (cbkxx != null) {
            YhCbkxxLog after = new YhCbkxxLog();
            BeanUtils.copyProperties(cbkxx, after);
            after.setCzsj(logCzsj);
            after.setLogLsh(logLsh);
            after.setLogCzryxm(logCzryxm);
            after.setLogCzrybm(logCzrybm);
            after.setLogCzsj(logCzsj);
            after.setLogId(GuidGenerator.getGuid());
            after.setLogCzlx(logCzlx);
            after.setLogCllx(String.format("%s后", logCzlx));
            after.setLogBz(log_bz);
            yhCbkxxLogService.save(after);
        }
    }

    @Override
    public long getCountByYhbh(String yhbh) {
        if (StrUtil.isEmpty(yhbh)) {
            return 0;
        }

        LambdaQueryWrapper<YhCbkxx> wrapper = Wrappers.<YhCbkxx>lambdaQuery()
                .eq(YhCbkxx::getYhbh, yhbh);
        return baseMapper.selectCount(wrapper);
    }


    @Override
    public List<YhCbkxx> getListCbkxxByYhbh(List<String> yhbhs) {
        if (yhbhs == null || yhbhs.isEmpty()) return new ArrayList<>();
        return this.list(Wrappers.lambdaQuery(YhCbkxx.class).in(YhCbkxx::getYhbh, yhbhs));
    }

}
