package com.tofly.feesapi.cbgl.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
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.service.YhCbkxxService;
import com.tofly.feesapi.bmgl.entity.BmCbb;
import com.tofly.feesapi.bmgl.service.BmCbbService;
import com.tofly.feesapi.cbgl.entity.YyCblr;
import com.tofly.feesapi.cbgl.entity.YyCblrExcel;
import com.tofly.feesapi.cbgl.entity.YyCblrLs;
import com.tofly.feesapi.cbgl.entity.dto.*;
import com.tofly.feesapi.cbgl.entity.vo.*;
import com.tofly.feesapi.cbgl.service.YyCblrLsService;
import com.tofly.feesapi.cbgl.service.YyCblrService;
import com.tofly.feesapi.common.Excel.Constant;
import com.tofly.feesapi.common.Excel.ExcelExportFileTypeEnum;
import com.tofly.feesapi.common.Excel.ExcleFileUtil;
import com.tofly.feesapi.common.constant.CbbzEnum;
import com.tofly.feesapi.common.constant.JsbzEnum;
import com.tofly.feesapi.common.constant.ShbzEnum;
import com.tofly.feesapi.common.core.ResultRespone;
import com.tofly.feesapi.common.core.dto.PageDto;
import com.tofly.feesapi.common.core.vo.PageResult;
import com.tofly.feesapi.common.core.vo.ResultVo;
import com.tofly.feesapi.common.exception.FeesErrorCode;
import com.tofly.feesapi.common.exception.FeesException;
import com.tofly.feesapi.common.model.CollectionData;
import com.tofly.feesapi.common.util.GuidGenerator;
import com.tofly.feesapi.config.FilePathBean;
import com.tofly.feesapi.file.service.IFileInfoService;
import com.tofly.feesapi.mxcx.entity.vo.YsartjSelect;
import com.tofly.feesapi.security.auth.ToflyUser;
import com.tofly.feesapi.security.util.SecurityUtils;
import com.tofly.feesapi.sfgl.entity.dto.YyQfmxStatFilter;
import com.tofly.feesapi.sfgl.entity.vo.YyStat;
import com.tofly.feesapi.sfgl.service.YyQfmxService;
import com.tofly.feesapi.xtgl.service.ISyscommlogService;
import com.tofly.feesapi.xtgl.service.impl.SysGdcsbServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 抄表录入 xxx
 */
@Slf4j
@RestController
@RequestMapping("api/cbgl/yycblr")
@Api(tags = "抄表录入")
public class YyCblrController {

    @Autowired
    private FilePathBean filePathBean;
    @Autowired
    private YhCbkxxService cbkxxService;
    @Autowired
    private IFileInfoService iFileInfoService;
    @Autowired
    private YyCblrService yyCblrService;
    @Autowired
    private YyCblrLsService yyCblrLsService;
    @Autowired
    private YyQfmxService yyQfmxService;
    @Autowired
    private BmCbbService bmCbbService;
    @Autowired
    private ISyscommlogService syscommlogService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @ApiOperationSupport(order = 1)
    @GetMapping("/page")
    @ApiOperation(value = "查询抄表录入（分页）", tags = {"抄表计划", "抄表照片管理", "抄表算费"})
    public ResultRespone<PageResult<YyCblrSelect>> getPage(@ModelAttribute PageDto pageDto, @ModelAttribute YyCblrFilter filter) {
        return ResultRespone.success(yyCblrService.getPage(pageDto, filter));
    }

    @GetMapping("/lycbglfy")
    @ApiOperation("莱阳-抄表管理计划分页查询")
    public ResultRespone<PageResult<YyCblrSelect>> lycbglfy(@ModelAttribute PageDto pageDto, @ModelAttribute YyCblrFilter filter) {
        return ResultRespone.success(yyCblrService.lycbglfy(pageDto, filter));
    }

    @ApiOperationSupport(order = 2)
    @GetMapping("/{yhbh}_{cbkh}")
    @ApiOperation(value = "查看抄表录入", tags = {"抄表照片管理"})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "yhbh", value = "用户编号", required = true, dataType = "String"),
            @ApiImplicitParam(name = "cbkh", value = "抄表卡号", required = true, dataType = "String")
    })
    public ResultRespone<YyCblrView> getById(@PathVariable("yhbh") String yhbh, @PathVariable("cbkh") String cbkh) {
        return ResultRespone.success(yyCblrService.getViewById(yhbh, cbkh));
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "生成抄表录入记录")
    @PostMapping
    public ResultRespone<Boolean> sccblr() {
        yyCblrService.sccblr();
        return ResultRespone.success(true);
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "修改抄表录入(抄表)")
    @PutMapping
    public ResultRespone<Boolean> update(@RequestBody YyCblrUpdate update) {
        return ResultRespone.success(yyCblrService.update(update));
    }

    @ApiOperationSupport(order = 5)
    @GetMapping("/page2")
    @ApiOperation(value = "查询抄表录入（含历史记录）（分页）")
    public ResultRespone<CblrCountSelect> getPage2(@ModelAttribute PageDto pageDto, @ModelAttribute YyCblrFilter filter) {
        return ResultRespone.success(yyCblrService.getPage2(pageDto, filter));
    }

    @ApiOperationSupport(order = 15)
    @GetMapping("/export")
    @ApiOperation(value = "导出抄表录入(抄表计划)", tags = "抄表计划")
    public void export(HttpServletResponse response, @ModelAttribute YyCblrFilter filter) throws IOException {
        List<YyCblrSelect> list = yyCblrService.getList(filter);
        if (!list.isEmpty()) {
            ExcleFileUtil.exportExcel(response, list, YyCblrSelect.class, "抄表计划.xlsx", filter.getExportFields());
        }
    }

    @ApiOperationSupport(order = 16)
    @GetMapping("/cbsltj")
    @ApiOperation(value = "抄表水量统计", tags = {"抄表水量统计"})
    public ResultRespone<CollectionData<CbSltjSelect>> cbsltj(@ModelAttribute YyCblrtjFilter filter) {
        if (StringUtil.isEmpty(filter.getCwrq())) {
            throw new FeesException("财务日期不能为空", FeesErrorCode.BUSINESS_ERROR);
        }

        if (StringUtil.isEmpty(filter.getTjlb())) {
            throw new FeesException("统计类别不能为空", FeesErrorCode.BUSINESS_ERROR);
        }

        List<CbSltjSelect> list = yyCblrService.cbsltj(filter);
        return ResultRespone.success(new CollectionData<>(list, list.size()));
    }

    @ApiOperationSupport(order = 17)
    @GetMapping("/cbsltj/export")
    @ApiOperation(value = "导出抄表水量统计", tags = {"抄表水量统计"})
    public void cbsltjExport(HttpServletResponse response, @ModelAttribute YyCblrtjFilter filter) throws IOException {
        if (StringUtil.isEmpty(filter.getCwrq())) {
            throw new FeesException("财务日期不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtil.isEmpty(filter.getTjlb())) {
            throw new FeesException("统计类别不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        List<CbSltjSelect> list = yyCblrService.cbsltj(filter);
        Properties properties = new Properties();
        if (filter.getTjlb().equals("cbry")) {
            properties.put("tjlb", "抄表人员");
        } else if (filter.getTjlb().equals("ysxz")) {
            properties.put("tjlb", "用水性质");
        } else if (filter.getTjlb().equals("cbb")) {
            properties.put("tjlb", "抄表本");
        }
        if (!list.isEmpty()) {
            ExcleFileUtil.exportExcel(response, list, CbSltjSelect.class, "抄表水量统计.xlsx", filter.getExportFields(), properties);
        }
    }

    @ApiOperationSupport(order = 18)
    @GetMapping("/cbltj")
    @ApiOperation(value = "抄表率统计", tags = {"抄表率统计"})
    public ResultRespone<CollectionData<CbltjSelect>> cbltj(@ModelAttribute YyCblrtjFilter filter) {
        if (StringUtil.isEmpty(filter.getCwrq())) {
            throw new FeesException("财务日期不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtil.isEmpty(filter.getTjlb())) {
            throw new FeesException("统计类别不能为空", FeesErrorCode.BUSINESS_ERROR);
        }
        List<CbltjSelect> cbltj = yyCblrService.cbltj(filter);
        return ResultRespone.success(new CollectionData<>(cbltj, cbltj.size()));
    }

    @ApiOperationSupport(order = 19)
    @GetMapping("/cbltj/export")
    @ApiOperation(value = "导出抄表率统计", tags = {"抄表率统计", "excel导出"})
    public void cbltjExport(HttpServletResponse response, @ModelAttribute YyCblrtjFilter filter) throws IOException {

        if (StringUtil.isEmpty(filter.getCwrq())) {
            throw new FeesException("财务日期不能为空", FeesErrorCode.BUSINESS_ERROR);
        }

        if (StringUtil.isEmpty(filter.getTjlb())) {
            throw new FeesException("统计类别不能为空", FeesErrorCode.BUSINESS_ERROR);
        }

        List<CbltjSelect> list = yyCblrService.cbltj(filter);
        Properties properties = new Properties();
        if (filter.getTjlb().equals("cbry")) {
            properties.put("tjlb", "抄表人员");
        } else if (filter.getTjlb().equals("cbb")) {
            properties.put("tjlb", "抄表本");
        }
        if (!list.isEmpty()) {
            ExcleFileUtil.exportExcel(response, list, CbltjSelect.class, "抄表率统计.xlsx", filter.getExportFields(), properties);
        }
    }

    @ApiOperationSupport(order = 20)
    @GetMapping("/cbycmx")
    @ApiOperation(value = "查询抄表异常明细", tags = {"抄表异常明细"})
    public ResultRespone<PageResult<YyCbycmxSelect>> cbycmx(@ModelAttribute PageDto pageDto, @ModelAttribute YyCbycmxFilter filter) {
        return ResultRespone.success(yyCblrService.cbycmx(pageDto, filter));
    }

    @ApiOperationSupport(order = 21)
    @GetMapping("/cbycmx/export")
    @ApiOperation(value = "导出抄表异常明细", tags = {"抄表异常明细", "excel导出"})
    public void cbycmxExport(HttpServletResponse response, @ModelAttribute YyCbycmxFilter filter) throws IOException {
        List<YyCbycmxSelect> list = yyCblrService.cbycmx(filter);
        if (!list.isEmpty()) {
            ExcleFileUtil.exportExcel(response, list, YyCbycmxSelect.class, "抄表异常明细.xlsx", filter.getExportFields());
        }
    }

    @ApiOperationSupport(order = 22)
    @PostMapping("/app/upload")
    @ApiOperation(value = "App数据上传", tags = {"App数据上传"})
    public ResultRespone appUpload(@ModelAttribute AppCblrUpload filter, @RequestParam(value = "fileList", required = false) List<MultipartFile> fileList) {
        ResultRespone<Object> rest = new ResultRespone<>();
        String cwrq = filter.getCwrq();
        try {
            Date date = new Date();
            ResultVo result = this.yyCblrService.appUploadInfo(filter, date);
            if (result.getCode() == 1) {
                String path = filePathBean.getCbfile();
                iFileInfoService.saveFileList(fileList, path, filter.getYhbh(), "yy_cblr", cwrq + "-" + new SimpleDateFormat("yyyyMMddHHmmss").format(date));
            }
            rest.setCode(result.getCode());

            rest.setMessage(result.getMsg());
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    @ApiOperationSupport(order = 23)
    @PutMapping("/cbshagx")
    @ApiOperation(value = "抄表审核按勾选", tags = {"抄表审核", "普表抄表管理"})
    public ResultRespone cbshagx(@RequestBody YyCblrSh yyCblrSh) {
        if (StringUtil.isNull(yyCblrSh.getCbkids()) || yyCblrSh.getCbkids().isEmpty()) {
            throw new FeesException("抄表卡ID信息不能为空！", FeesErrorCode.BUSINESS_ERROR);
        }
        if (StringUtil.isEmpty(yyCblrSh.getShbz())) {
            throw new FeesException("审核状态不能为空！", FeesErrorCode.BUSINESS_ERROR);
        }
        if (!yyCblrSh.getShbz().equals("1") && !yyCblrSh.getShbz().equals("2")) {
            throw new FeesException("审核状态只能为1（审核通过）或2（审核不通过）！", FeesErrorCode.BUSINESS_ERROR);
        }
        long count = yyCblrService.lambdaQuery()
                .in(YyCblr::getCbkid, yyCblrSh.getCbkids())
                .eq(YyCblr::getShbz, ShbzEnum.未审核)
                .count();
        if (count != yyCblrSh.getCbkids().size()) {
            throw new FeesException("勾选抄表审核记录存在不是未审核记录！", FeesErrorCode.BUSINESS_ERROR);
        }

        if (yyCblrService.lambdaUpdate()
                .in(YyCblr::getCbkid, yyCblrSh.getCbkids())
                .set(YyCblr::getShbz, yyCblrSh.getShbz())
                .set(YyCblr::getShry, SecurityUtils.getUserId().toString())
                .set(YyCblr::getShryxm, SecurityUtils.getUser().getRealName())
                .set(YyCblr::getShsj, new Date())
                .update()) {
            return ResultRespone.success(true, "审核成功");
        }
        return ResultRespone.failed("审核失败");
    }

    @ApiOperationSupport(order = 24)
    @PutMapping("/cbshatj")
    @ApiOperation(value = "抄表审核按条件", tags = {"抄表审核", "普表抄表管理"})
    @Transactional
    public ResultRespone cbshatj(@RequestBody YyCblrFilter filter) {
        if (!filter.getShbz().equals(ShbzEnum.未审核)) {
            filter.setShbz(ShbzEnum.未审核);
        }
        List<String> cbkids = yyCblrService.getCbkids(filter);
        if (cbkids.isEmpty()) {
            return ResultRespone.failed("未找到未审核记录");
        }
        List<List<String>> cblrList = Lists.partition(cbkids, 1000);
        for (List<String> e : cblrList) {
            yyCblrService.lambdaUpdate()
                    .in(YyCblr::getCbkid, e)
                    .set(YyCblr::getShbz, ShbzEnum.审核通过)
                    .set(YyCblr::getShry, SecurityUtils.getUserId().toString())
                    .set(YyCblr::getShryxm, SecurityUtils.getUser().getRealName())
                    .set(YyCblr::getShsj, new Date())
                    .update();
        }
        return ResultRespone.success(true, "审核成功");
    }

    /**
     * 获取抄表录入
     */
    @ApiOperationSupport(order = 1)
    @GetMapping("/getNotCblr")
    @ApiOperation(value = "未抄表用户统计", tags = {"明细查询"})
    public ResultRespone<CblrCountSelect> getCblr(@ModelAttribute PageDto pageDto, YyCblrFilter filter) {
        return ResultRespone.success(yyCblrService.getPage2(pageDto, filter));
    }

    @GetMapping("/wcbmx/export")
    @ApiOperation(value = "未抄表export导出", tags = {"excel导出"})
    public void wcbexport(HttpServletResponse response, YyCblrFilter filter) throws IOException {
        List<YyCblrSelect> list = yyCblrService.getList(filter);
        if (!list.isEmpty()) {
            //导出excle
            ExcleFileUtil.exportExcel(response, list, YyCblrSelect.class, "未抄表录入.xlsx", filter.getExportFields());
        }
    }

    @GetMapping("/cbmx/export")
    @ApiOperation(value = "抄表明细导出", tags = {"excel导出"})
    public void cbmxexport(HttpServletResponse response, YyCblrFilter filter) throws IOException {
        List<YyCblrSelect> list = yyCblrService.getListCbmx(filter);
        if (!list.isEmpty()) {
            //导出excle
            ExcleFileUtil.exportExcel(response, list, YyCblrSelect.class, "抄表明细查询.xlsx", filter.getExportFields());
        }
    }

    @ApiOperationSupport(order = 21)
    @GetMapping("/stat")
    @ApiOperation(value = "抄表信息统计", tags = {"综合查询"})
    public ResultRespone<YyStat> stat(@ModelAttribute YyQfmxStatFilter filter) {
        YyStat stat = yyCblrService.stat(filter);
        return ResultRespone.success(stat);
    }

    @ApiOperationSupport(order = 22)
    @PostMapping("/adddccb")
    @ApiOperation(value = "增加多次抄表", tags = {"抄表计划"})
    @Transactional(rollbackFor = FeesException.class)
    public ResultRespone adddccb(@RequestBody List<String> cbkids) {
        List<YyCblr> yyCblrList = yyCblrService.list(
                new QueryWrapper<YyCblr>().lambda()
                        .in(YyCblr::getCbkid, cbkids)
        );
        if (yyCblrList.size() == 0) {
            throw new FeesException("参数错误，没有查询到抄表计划！", FeesErrorCode.BUSINESS_ERROR);
        }

        long count = yyCblrList.stream().filter(e -> e.getJsbz().equals(JsbzEnum.未算费)).count();
        if (count > 0) {
            throw new FeesException("存在算费的抄表计划，无法新增！", FeesErrorCode.BUSINESS_ERROR);
        }

        List<YyCblrLs> yyCblrLsList = new ArrayList<>();
        List<BmCbb> bmCbbList = bmCbbService.list();
        for (YyCblr yyCblr : yyCblrList) {
            YyCblrLs yyCblrLs = new YyCblrLs();
            BeanUtils.copyProperties(yyCblr, yyCblrLs);
            yyCblrLs.setId(GuidGenerator.getGuid());
            BmCbb bmCbb = bmCbbList.stream().filter(e -> e.getCbbbm().equals(yyCblr.getSscbb())).findFirst().orElse(null);
            if (StringUtil.isNotNull(bmCbb)) {
                yyCblrLs.setQyfzrbm(bmCbb.getQyfzr());
                yyCblrLs.setQyfzrxm(bmCbb.getQyfzrxm());
            }
            yyCblrLsList.add(yyCblrLs);
        }
        boolean tf = yyCblrLsService.saveBatch(yyCblrLsList);
        if (!tf) {
            throw new FeesException("结转抄表记录失败！", FeesErrorCode.BUSINESS_ERROR);
        }
        tf = yyCblrService.lambdaUpdate()
                .setSql("SCDS=BCDS")
                .setSql("CBCS=CBCS+1")
                .set(YyCblr::getJjl, 0)
                .set(YyCblr::getSl, 0)
                .set(YyCblr::getCbryxm, "")
                .set(YyCblr::getCbrybm, "")
                .set(YyCblr::getCbrq, "")
                .set(YyCblr::getLrrq, "")
                .set(YyCblr::getLrrybm, "")
                .set(YyCblr::getLrryxm, "")
                .set(YyCblr::getPhoto, "")
                .set(YyCblr::getCbbz, CbbzEnum.未抄表)
                .set(YyCblr::getShbz, ShbzEnum.未审核)
                .set(YyCblr::getJsbz, JsbzEnum.未算费)
                .set(YyCblr::getBz, "")
                .set(YyCblr::getCblx, "0")
                .set(YyCblr::getCbfs, "01")
                .set(YyCblr::getCbly, "0")
                .set(YyCblr::getJbzd, 0)
                .set(YyCblr::getXbqd, 0)
                .in(YyCblr::getCbkid, cbkids)
                .eq(YyCblr::getJsbz, JsbzEnum.已算费)
                .eq(YyCblr::getCbbz, CbbzEnum.已抄表)
                .eq(YyCblr::getShbz, ShbzEnum.审核通过)
                .update();
        if (!tf) {
            throw new FeesException("抄表计划重置失败！", FeesErrorCode.BUSINESS_ERROR);
        }
        return ResultRespone.success(tf);
    }

    @ApiOperationSupport(order = 23)
    @ApiOperation(value = "批量抄表", tags = {"抄表录入"})
    @PostMapping("/plcb")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", required = true, dataType = "__File", paramType = "form"),
            @ApiImplicitParam(name = "lrlx", value = "录入类型(1普表、2远传表)", required = true, dataType = "String", paramType = "form")
    })
    public ResultRespone plcb(@RequestParam("file") MultipartFile file, String lrlx) {
        try {

            String path = filePathBean.getCbfile();
            List<MultipartFile> files = new ArrayList<>();
            files.add(file);
            iFileInfoService.saveFileList(files, path, SecurityUtils.getUserId().toString(), "yy_cblr", "", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "抄表批量导入文件");
            List<YyCblrExcel> yyCblrExcelList = EasyExcel.read(file.getInputStream()).head(YyCblrExcel.class).sheet().doReadSync();
            //由于SQL过长以及in查询不能超过1000所以采取分段查询
            List<List<String>> cblrList = Lists.partition(yyCblrExcelList.stream()
                    .map(YyCblrExcel::getYhbh).filter(e -> StringUtil.isNotEmpty(e))
                    .collect(Collectors.toList()), 1000);
            List<YhCbkxx> cbkxxes = new ArrayList<>();
            List<YyCblr> yyCblrList = new ArrayList<>();
            for (List<String> cblrList1 : cblrList) {
                LambdaQueryWrapper<YhCbkxx> cbkxxQueryWrapper = new LambdaQueryWrapper<>();
                cbkxxQueryWrapper.select(
                        YhCbkxx::getYhbh, YhCbkxx::getCbkh,
                        YhCbkxx::getCbkid, YhCbkxx::getYbdjbz,
                        YhCbkxx::getSjbm, YhCbkxx::getSlbl,
                        YhCbkxx::getSjbm1, YhCbkxx::getSlbl1,
                        YhCbkxx::getSjbm2, YhCbkxx::getSlbl2,
                        YhCbkxx::getSjbm3, YhCbkxx::getSlbl3,
                        YhCbkxx::getWsfbz, YhCbkxx::getSzyfbz,
                        YhCbkxx::getSbyt, YhCbkxx::getSblb,
                        YhCbkxx::getLjfbz, YhCbkxx::getLjffs, YhCbkxx::getLjfje);
                cbkxxQueryWrapper.in(YhCbkxx::getYhbh, cblrList1);
                List<YhCbkxx> cbkxxes1 = cbkxxService.list(cbkxxQueryWrapper);
                cbkxxes.addAll(cbkxxes1);
                yyCblrList.addAll(yyCblrService.lambdaQuery()
                        .in(YyCblr::getCbkid, cbkxxes1.stream().map(YhCbkxx::getCbkid).collect(Collectors.toList()))
                        .list());
            }
            // 创建可配置线程池
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    Runtime.getRuntime().availableProcessors() * 2,  // 核心线程数
                    Runtime.getRuntime().availableProcessors() * 4,  // 最大线程数
                    60L, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(2000),
                    new ThreadPoolExecutor.CallerRunsPolicy()
            );
            AtomicInteger cgnum = new AtomicInteger();
            StringBuilder msg = new StringBuilder();
            StringBuilder msg2 = new StringBuilder();
            StringBuilder msg3 = new StringBuilder();
            StringBuilder msg5 = new StringBuilder();
            StringBuilder msg6 = new StringBuilder();
            AtomicReference<String> msg4 = new AtomicReference<>("");
            try {
                ToflyUser loginUser = SecurityUtils.getUser();
                List<CompletableFuture<Void>> futures = yyCblrExcelList
                        .stream()
                        .map(yyCblrExcel -> CompletableFuture.runAsync(() -> {
                            int ret = transactionTemplate.execute(status -> {
                                try {
                                    System.out.println("开始处理：" + yyCblrExcel.getYhbh());
                                    if (StringUtil.isEmpty(yyCblrExcel.getYhbh())) {
                                        msg4.set("Excel存在用户编号为空的记录");
                                        return 0;
                                    }
                                    if (StringUtil.isNotNull(yyCblrExcel.getBcds())) {
                                        if (StringUtil.isEmpty(yyCblrExcel.getCbkh())) {
                                            yyCblrExcel.setCbkh("1");
                                        }
                                        YhCbkxx cbkxx = cbkxxes.stream().filter(e ->
                                                        e.getYhbh().equals(yyCblrExcel.getYhbh()) &&
                                                                e.getCbkh().equals(yyCblrExcel.getCbkh()))
                                                .findFirst().orElse(null);
                                        if (StringUtil.isNull(cbkxx)) {
                                            msg2.append(yyCblrExcel.getYhbh()).append("，");
                                            return 0;
                                        }
                                        if (cbkxx != null && lrlx.equals("1") && cbkxx.getSblb().equals("2")) {
                                            msg3.append(yyCblrExcel.getYhbh()).append("，");
                                            return 0;
                                        }
                                        if (cbkxx != null && lrlx.equals("2") && !cbkxx.getSblb().equals("2")) {
                                            msg3.append(yyCblrExcel.getYhbh()).append("，");
                                            return 0;
                                        }
                                        YyCblr yyCblr = yyCblrList.stream().filter(e ->
                                                e.getYhbh().equals(yyCblrExcel.getYhbh()) &&
                                                        e.getCbkid().equals(cbkxx.getCbkid())).findFirst().orElse(null);
                                        if (StringUtil.isNull(yyCblr)) {
                                            msg2.append(yyCblrExcel.getYhbh()).append("，");
                                            return 0;
                                        }
                                        if (yyCblr.getJsbz().equals(JsbzEnum.已算费)) {
                                            msg2.append(yyCblrExcel.getYhbh()).append("，");
                                            return 0;
                                        }
//                                        if (yyCblr.getCbbz().equals(CbbzEnum.已抄表)) {
//                                            return 0;
//                                        }
                                        yyCblr.setCbbz(CbbzEnum.已抄表);
                                        yyCblr.setCbrq(yyCblrExcel.getCbrq());
                                        yyCblr.setLrrq(new Date());
                                        yyCblr.setCbfs("1");
                                        yyCblr.setCbly("4");
                                        BigDecimal ysl;
                                        if (yyCblrExcel.getHbzz() != null && yyCblrExcel.getHbzz().compareTo(BigDecimal.ZERO) > 0) {
                                            yyCblr.setJbzd(yyCblrExcel.getHbzz());
                                            yyCblr.setXbqd(yyCblrExcel.getXbcszz());
                                            yyCblr.setBcds(yyCblrExcel.getBcds());
                                            yyCblr.setCblx("-3");
                                            //新表水量与旧表水量计算
                                            ysl = yyCblrExcel.getBcds().subtract(yyCblrExcel.getXbcszz())
                                                    .add(yyCblrExcel.getHbzz().subtract(yyCblr.getScds()));

                                        } else {
                                            yyCblr.setCblx("0");
                                            yyCblr.setBcds(yyCblrExcel.getBcds());
                                            ysl = yyCblrExcel.getBcds().subtract(yyCblr.getScds());
                                            if (ysl.compareTo(BigDecimal.ZERO) < 0) {
                                                msg5.append(yyCblrExcel.getYhbh()).append("，");
                                                return 0;
                                            }
                                        }

                                        if (!yyCblr.getScds().equals(yyCblrExcel.getScds())) {
                                            //msg2.append(yyCblr.getYhbh() + "：EXCEL录入上次指针与系统上次指针不匹配.");
                                            msg5.append(yyCblr.getYhbh());
                                            return 0;
                                        }
                                        if (!ysl.equals(yyCblrExcel.getYsl())) {
                                            //msg2.append(yyCblr.getYhbh() + "水量不等");
                                            msg6.append(yyCblr.getYhbh());
                                            return 0;
                                        }
                                        yyCblr.setSl(ysl);
                                        yyCblr.setShbz(ShbzEnum.审核通过); //默认为审核通过
                                        //yyCblr.setCbryxm(loginUser.getRealName());
                                        //yyCblr.setCbrybm(loginUser.getUserid().toString());
                                        yyCblr.setLrryxm(loginUser.getRealName());
                                        yyCblr.setLrrybm(loginUser.getUserid().toString());
                                        if (StringUtil.isNotEmpty(yyCblrExcel.getSbzt())) {
                                            switch (yyCblrExcel.getSbzt().trim()) {
                                                case "正常":
                                                    yyCblr.setSbzt("1");
                                                    break;
                                                case "水表起始流量":
                                                    yyCblr.setSbzt("2");
                                                    break;
                                                case "水表模糊":
                                                    yyCblr.setSbzt("3");
                                                    break;
                                                case "不用":
                                                    yyCblr.setSbzt("4");
                                                    break;
                                                case "表停":
                                                    yyCblr.setSbzt("5");
                                                    break;
                                                case "锁门":
                                                    yyCblr.setSbzt("6");
                                                    break;
                                                case "堆压":
                                                    yyCblr.setSbzt("7");
                                                    break;
                                                case "加前表":
                                                    yyCblr.setSbzt("8");
                                                    break;
                                                case "私接":
                                                    yyCblr.setSbzt("9");
                                                    break;
                                                case "翻表":
                                                    yyCblr.setSbzt("10");
                                                    break;
                                                case "未知抄表":
                                                    yyCblr.setSbzt("11");
                                                    break;
                                                case "拆表":
                                                    yyCblr.setSbzt("12");
                                                    break;
                                                case "污水表":
                                                    yyCblr.setSbzt("13");
                                                    break;
                                                case "表黑":
                                                    yyCblr.setSbzt("14");
                                                    break;
                                                case "表倒":
                                                    yyCblr.setSbzt("15");
                                                    break;
                                                case "表烂":
                                                    yyCblr.setSbzt("16");
                                                    break;
                                            }
                                            if (yyCblrService.updateById(yyCblr)) {
                                                return 1;
                                            }
                                        }
                                        else {
                                            yyCblr.setSbzt("1");
                                        }
                                    }
                                    msg2.append(yyCblrExcel.getYhbh()).append("，");
                                    return 0;
                                } catch (Exception e) {
                                    status.setRollbackOnly();
                                    return 0;
                                }
                            });
                            cgnum.addAndGet(ret);
                        }, executor))
                        .collect(Collectors.toList());
                // 等待所有任务完成
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            } finally {
                executor.shutdown();
            }
            if (yyCblrExcelList.size() - cgnum.get() > 0) {
                int failnum = yyCblrExcelList.size() - cgnum.get();
                msg.insert(0, "成功导入数：" + cgnum + ";失败数" + failnum + "-用户：");
                if (StringUtil.isNotEmpty(msg2.toString())) {
                    msg.append(";用户信息不存在或抄表已算费").append(msg2);
                }
                if (StringUtil.isNotEmpty(msg4.get())) {
                    msg.append(";").append(msg4);
                }
                if (StringUtil.isNotEmpty(msg5.toString())) {
                    msg.append(";抄表指针存在问题：").append(msg5);
                }
                if (StringUtil.isNotEmpty(msg6.toString())) {
                    msg.append(";水量不等：").append(msg6);
                }
                if (msg3.length() > 0) {
                    if (lrlx.equals("1")) {
                        msg.append(";不是普表用户：").append(msg3);
                    } else {
                        msg.append(";不是远传表用户：").append(msg3);
                    }
                }
            } else {
                msg = new StringBuilder("全部成功导入");
            }
            return ResultRespone.success(msg.toString());

        } catch (IOException ex) {
            ex.printStackTrace();
            throw new FeesException("导入失败", FeesErrorCode.BUSINESS_ERROR);
        }
    }

    @ApiOperationSupport(order = 24)
    @ApiOperation(value = "导出抄表计划（批量抄表）", tags = {"抄表录入"})
    @GetMapping("/exportcbjh")
    public void exportcbjh(HttpServletResponse response, @ModelAttribute YyCblrFilter filter) {
        List<YyCblrSelect> list = yyCblrService.getList(filter);
        ExcelExportFileTypeEnum excelExportFileTypeEnum = ExcelExportFileTypeEnum.getExcelExportFileTypeEnum("plcb_cbjh", "1");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("list", list);
        ExcleFileUtil.export(dataMap, excelExportFileTypeEnum, Constant.FILE_PATH_TEST_EXPORT_EXCEL, response);
    }


    @ApiOperationSupport(order = 24)
    @ApiOperation(value = "水量分析统计报表", tags = {"统计报表"})
    @GetMapping("/getSlfxTjbb")
    public ResultRespone getSlfxTjbb(@ModelAttribute CblrSflxFilter filter) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        rest.setResult(yyCblrService.getSlfxtj1(filter));
        return rest;
    }


    @ApiOperationSupport(order = 24)
    @ApiOperation(value = "水量分析明细统计报表", tags = {"统计报表"})
    @GetMapping("/getSlfxMxTjbb")
    public ResultRespone getSlfxMxTjbb(@ModelAttribute PageDto pageDto, CblrSflxFilter filter) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        rest.setResult(yyCblrService.getSllxfxReport(pageDto, filter));
        return rest;
    }

    @ApiOperationSupport(order = 25)
    @GetMapping("/plcbexport")
    @ApiOperation(value = "批量抄表模版下载（带数据）", tags = "批量抄表")
    public void plcbexport(HttpServletResponse response, @ModelAttribute YyCblrFilter filter) throws IOException {
        List<YyCblrSelect> list = yyCblrService.getList(filter);
        if (!list.isEmpty()) {
            List<YyCblrExcel> yyCblrExcelList = list.stream().map(item -> {
                        YyCblrExcel yyCblrExcel = new YyCblrExcel();
                        yyCblrExcel.setYhbh(item.getYhbh());
                        yyCblrExcel.setScds(item.getScds());
                        return yyCblrExcel;
                    })
                    .sorted(Comparator.comparing(YyCblrExcel::getYhbh))
                    .collect(Collectors.toList());
            if (StringUtil.isEmpty(filter.getExportFields())) {
                filter.setExportFields("yhbh,cbrq,scds,bcds,hbzz,ysl,xbcszz");
            }
            ExcleFileUtil.exportExcel(response, yyCblrExcelList, YyCblrExcel.class, "抄表计划.xlsx", filter.getExportFields());
        }
    }
    @ApiOperationSupport(order = 26)
    @ApiOperation(value = "月末结转手动执行")
    @GetMapping("/ymjzsd")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "key", value = "key值", required = true, dataType = "String")
    })
    public ResultRespone ymjzsd(String key) {
        if (!"Tofly@028".equals(key)) {
            return ResultRespone.failed("key输入错误");
        }
        yyCblrService.cbymjz();
        return ResultRespone.success("执行成功");
    }

}
