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

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tofly.feesapi.bjgl.entity.YhCbkxx;
import com.tofly.feesapi.bjgl.service.YhCbkxxService;
import com.tofly.feesapi.cbgl.entity.ZnbCbLog;
import com.tofly.feesapi.cbgl.entity.dto.ReadResult;
import com.tofly.feesapi.cbgl.entity.dto.ZnbCbLogFilter;
import com.tofly.feesapi.cbgl.entity.vo.ZnbCbLogSelect;
import com.tofly.feesapi.cbgl.mapper.ZnbCbLogMapper;
import com.tofly.feesapi.cbgl.service.CjService;
import com.tofly.feesapi.cbgl.service.IZnbCbLogService;
import com.tofly.feesapi.common.SmsService;
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.sfgl.entity.ZnbCsjsLog;
import com.tofly.feesapi.sfgl.service.IZnbCsjsLogService;
import com.tofly.feesapi.xtgl.service.ISysGdcsbService;
import com.tofly.feesapi.yhgl.entity.YhKhjbxx;
import com.tofly.feesapi.yhgl.service.IYyZjzhService;
import com.tofly.feesapi.yhgl.service.YhKhjbxxService;
import lombok.extern.slf4j.Slf4j;
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.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 智能表抄表明细 服务实现类
 * </p>
 *
 * @author decai
 * @since 2024-04-08
 */
@Slf4j
@Service
public class ZnbCbLogServiceImpl extends ServiceImpl<ZnbCbLogMapper, ZnbCbLog> implements IZnbCbLogService {

    @Autowired
    private YhCbkxxService cbkxxService;
    @Autowired
    private YhKhjbxxService khjbxxService;

    @Autowired
    private IZnbCsjsLogService znbCsjsLogService;

    @Autowired
    private ISysGdcsbService gdcsbService;

    @Autowired
    private IYyZjzhService zjzhService;

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

    @Autowired
    private SmsService smsService;

    @Override
    public PageResult<ZnbCbLogSelect> getPage(PageDto pageDto, ZnbCbLogFilter filter) {
        List<Order> orders = pageDto.getOrders();
        if (orders.isEmpty()) {
            orders.add(new Order("a.cbrq", false));
        }
        PageDto<ZnbCbLogSelect> page = this.baseMapper.getPage(pageDto, filter);
        return page.toVo();
    }

    @Override
    public List<ZnbCbLogSelect> getList(ZnbCbLogFilter filter) {
        return this.baseMapper.getList(filter);
    }

    @Override
    @Transactional
    public void batchRead() throws Exception {
        if (cjServices == null || cjServices.isEmpty()) {
            return;
        }

        for (Map.Entry<String, CjService> entry : cjServices.entrySet()) {
            String serviceName = entry.getKey();
            CjService cjService = entry.getValue();

            if (Thread.interrupted()) return;
            String[] nameParts = serviceName.split("#");
            if (nameParts.length < 2) {
                log.error("厂家服务名称错误");
                return;
            }
            String sbsccj = nameParts[1];
            String afterCbkid = null;
            int limit = 100;
            String sblb = "2";
            long count = cbkxxService.count(sblb, sbsccj);
            int times = (int) (count % limit == 0 ? count / limit : count / limit + 1);
            LocalDate cbrq = LocalDate.now().plusDays(-1);//抄表日期
            LocalDate sccbrq = cbrq.plusDays(-1);//上次抄表日期
            LocalDateTime czsj = LocalDateTime.now();
            String pch = getPch();
            String cwrq = gdcsbService.selectCwrq();

            for (int i = 0; i < times; i++) {
                if (Thread.interrupted()) return;

                List<YhCbkxx> cbkxxList = get(sblb, sbsccj, afterCbkid, 100);
                if (!cbkxxList.isEmpty()) {
                    int size = cbkxxList.size();
                    YhCbkxx maxCbkxx = cbkxxList.get(size - 1);
                    afterCbkid = maxCbkxx.getCbkid();
                }
                if (cjService != null) {
                    List<String> sbbhs = cbkxxList.stream()
                            .map(e -> e.getSbbh())
                            .distinct()
                            .collect(Collectors.toList());
                    List<ReadResult> readResults = cjService.read(sbbhs);
                    log.info("readResults:{}", readResults);
                    List<ZnbCbLog> lasCbList = getListBySbbh(sbbhs, sccbrq);
                    List<String> yhbhs = cbkxxList.stream()
                            .filter(Objects::nonNull)
                            .map(e -> e.getYhbh())
                            .distinct()
                            .collect(Collectors.toList());
                    List<YhKhjbxx> khjbxxList = khjbxxService.getListByYhbh(yhbhs);
                    Map<String, YhKhjbxx> khjbxxMap = khjbxxList.stream()
                            .collect(Collectors.toMap(YhKhjbxx::getYhbh, e -> e, (x, y) -> x));
                    Map<String, ZnbCbLog> scdsMap = lasCbList.stream()
                            .collect(Collectors.toMap(ZnbCbLog::getBjbh, e -> e, (x, y) -> x));
                    Map<String, BigDecimal> bcdsMap = readResults.stream()
                            .collect(Collectors.toMap(ReadResult::getSbbh, ReadResult::getBcds, (x, y) -> x));
                    List<ZnbCbLog> znbCbLogs = save(cbkxxList, pch, cbrq, cwrq, czsj, khjbxxMap, scdsMap, bcdsMap);
                    if (!znbCbLogs.isEmpty()) cjService.syncSyje(znbCbLogs);
                    List<ZnbCbLog> qfList = znbCbLogs.stream()
                            .filter(e -> e.getSyje().compareTo(BigDecimal.ZERO) <= 0)
                            .collect(Collectors.toList());//欠费
                    List<ZnbCbLog> txList = znbCbLogs.stream()
                            .filter(e -> e.getSyje().compareTo(BigDecimal.ZERO) > 0
                                    && e.getSyje().compareTo(BigDecimal.valueOf(10)) < 0)
                            .collect(Collectors.toList());//提醒
                    if (!qfList.isEmpty()) cjService.close(qfList);
                    if (!txList.isEmpty()) smsService.sendTx(txList);
                }
            }

        }
    }

    @Override
    public BigDecimal getLjl(String yhbh, LocalDateTime startTime, LocalDateTime endTime) {
        return this.baseMapper.getLjl(yhbh, startTime, endTime);
    }

    private String getPch() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    private List<ZnbCbLog> save(List<YhCbkxx> cbkxxList,
                                String pch,
                                LocalDate cbrq,
                                String cwrq,
                                LocalDateTime czsj,
                                Map<String, YhKhjbxx> khjbxxMap,
                                Map<String, ZnbCbLog> scdsMap,
                                Map<String, BigDecimal> bcdsMap) throws Exception{
        List<ZnbCbLog> cbLogs = new ArrayList<>();
        for (YhCbkxx cbkxx : cbkxxList) {
            String yhbh = cbkxx.getYhbh();
            String sbbh = cbkxx.getSbbh();
            YhKhjbxx khjbxx = khjbxxMap.get(yhbh);
            if (khjbxx == null) continue;
            ZnbCbLog scCbLog = scdsMap.get(sbbh);
            BigDecimal scds = scCbLog == null ? BigDecimal.ZERO : scCbLog.getBcds();
            BigDecimal bcds = bcdsMap.getOrDefault(sbbh, BigDecimal.ZERO);
            if (scds != null && bcds.compareTo(scds) < 0) {
                log.warn("本次读数({})小于上次读数({}):{}", bcds, scds, sbbh);
                continue;
            }

            ZnbCbLog znbCbLog = getBySbbh(sbbh, cbrq);
            if (znbCbLog != null) {
                log.warn("已抄表:{}({})", sbbh, cbrq.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
                continue;
            }
            znbCbLog = new ZnbCbLog();
            BeanUtils.copyProperties(khjbxx, znbCbLog);
            BeanUtils.copyProperties(cbkxx, znbCbLog);
            znbCbLog.setBjbh(sbbh);
            znbCbLog.setPch(pch);
            znbCbLog.setCwrq(cwrq);
            znbCbLog.setScds(scds);
            znbCbLog.setSccj(cbkxx.getSbsccj());
            znbCbLog.setSccbrq(scCbLog == null ? null : scCbLog.getCbrq());
            znbCbLog.setBcds(bcds);
            znbCbLog.setCbrq(cbrq);
            znbCbLog.setCzsj(czsj);
            znbCbLog.setClClsj(LocalDateTime.now());
            this.saveOrUpdate(znbCbLog);
            ZnbCsjsLog csjsLog = znbCsjsLogService.csjs(cbkxx, khjbxx, cwrq, scds, bcds, znbCbLog.getId());
            if (csjsLog == null) continue;
            BigDecimal syje = cbkxx.getSyje() == null ? BigDecimal.ZERO : cbkxx.getSyje();
            BigDecimal yssf = csjsLog.getYssf();
            syje = syje.subtract(yssf);
            znbCbLog.setSyje(syje);
            cbkxxService.updateSyje(cbkxx.getCbkid(), syje);
            this.updateSyje(znbCbLog.getId(), syje);
            cbLogs.add(znbCbLog);

        }
        return cbLogs;
    }

    private void updateSyje(String id, BigDecimal syje) {
        this.lambdaUpdate()
                .eq(ZnbCbLog::getId, id)
                .set(ZnbCbLog::getSyje, syje)
                .update();
    }

    private ZnbCbLog getBySbbh(String sbbh, LocalDate date) {
        List<ZnbCbLog> cbLogs = this.getListBySbbh(Arrays.asList(sbbh), date);
        if (!cbLogs.isEmpty()) return cbLogs.get(0);
        return null;
    }

    private List<ZnbCbLog> getListBySbbh(List<String> sbbhs, LocalDate date) {
        if (sbbhs == null || sbbhs.isEmpty() || date == null) return new ArrayList<>();
        return this.list(Wrappers.lambdaQuery(ZnbCbLog.class).in(ZnbCbLog::getBjbh, sbbhs)
                .between(ZnbCbLog::getCbrq, LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX)));
    }

    private List<YhCbkxx> get(String sblb, String sbsccj, String afterCbkid, int limit) {
        return cbkxxService.getListByAfterCbkid(sblb, sbsccj, afterCbkid, limit);
    }
}
