package cn.com.victorysoft.business.calc.service;

import cn.com.victorysoft.business.calc.dao.DataSyncDao;
import cn.com.victorysoft.business.calc.entity.SysInjectTechnology;
import cn.com.victorysoft.business.constant.DataType;
import cn.com.victorysoft.business.indicator.dao.WellSectionMonthDao;
import cn.com.victorysoft.business.indicator.entity.WellSectionMonth;
import cn.com.victorysoft.business.indicator.param.WellSectionMonthParam;
import cn.com.victorysoft.business.indicator.service.SectionRateSummaryService;
import cn.com.victorysoft.business.indicator.service.UnitMonthService;
import cn.com.victorysoft.business.indicator.service.WellSectionMonthService;
import cn.com.victorysoft.business.sys.dao.WellSectionDailyDao;
import cn.com.victorysoft.business.sys.entity.DateRange;
import cn.com.victorysoft.business.sys.entity.WellSectionDaily;
import cn.com.victorysoft.business.sys.param.UnitDateRangeParam;
import cn.com.victorysoft.business.util.BeanUtils;
import cn.com.victorysoft.business.util.DateUtils;
import cn.com.victorysoft.business.util.StringUtils;
import cn.com.victorysoft.business.util.UuidUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static cn.com.victorysoft.business.indicator.constant.Constants.*;

/**
 * 数据同步服务
 */
@Slf4j
@Service
public class DataSyncService {

    @Resource
    private WellSectionDailyDao wellSectionDailyDao;
    @Resource
    private WellSectionMonthDao wellSectionMonthDao;
    @Resource
    private DataSyncDao dataSyncDao;
    @Resource
    private UnitMonthService unitMonthService;
    @Resource
    private WellSectionMonthService wellSectionMonthService;
    @Resource
    private SectionRateSummaryService sectionRateSummaryService;

    /**
     * 静态数据
     */
    @Transactional
    public void syncStaticData() {
        dataSyncDao.syncWaterWell();
    }

    /**
     * 同步注水层段日度数据
     */
    @Transactional
    public void syncWellSectionDaily(Date startDate, Date endDate) {
        // 先删除
        wellSectionDailyDao.deleteByDate(startDate, endDate);
        // 查询注水工艺
        List<SysInjectTechnology> technologyList = dataSyncDao.selectInjectTechnology();
        // 单注工艺代码
        List<String> singleCodes = technologyList.stream()
                .filter(item -> "单注".equals(item.getZsgy()))
                .map(SysInjectTechnology::getDm)
                .collect(Collectors.toList());
        // 分注工艺代码
        List<String> splitCodes = technologyList.stream()
                .filter(item -> "分注".equals(item.getZsgy()))
                .map(SysInjectTechnology::getDm)
                .collect(Collectors.toList());
        // 同步单注井数据
        dataSyncDao.syncSingleWellDaily(startDate, endDate, singleCodes);
        // 同步分注井数据
        dataSyncDao.syncWellSectionDaily(startDate, endDate, splitCodes);
        // 计算注水类型
        this.updateInjectType(startDate, endDate);
    }

    /**
     * 计算注水类型
     */
    public void updateInjectType(Date startDate, Date endDate) {
        // 查询注水工艺
        Map<String, SysInjectTechnology> technologyMap = dataSyncDao.selectInjectTechnology()
                .stream().collect(Collectors.toMap(SysInjectTechnology::getDm, v -> v));
        // 查询注水数据
        List<WellSectionDaily> list = wellSectionDailyDao.selectByDate(startDate, endDate);
        // 查找方停的井
        Map<String, Set<Integer>> stopWellNames = new HashMap<>();
        for (WellSectionDaily record : list) {
            String wellname = record.getWellname();
            Integer section = record.getSection();
            if (!stopWellNames.containsKey(wellname)) {
                stopWellNames.put(wellname, new HashSet<>());
            }
            if (record.getNozzle() != null && record.getNozzle().contains("方停")) {
                stopWellNames.get(wellname).add(section);
            }else {
                stopWellNames.get(wellname).remove(section);
            }
        }
        for (WellSectionDaily record : list) {
            String injectTypeYs = record.getInjectTypeYs();
            SysInjectTechnology technology = technologyMap.get(injectTypeYs);
            // 如果注水工艺不存在，不判断
            if (technology == null) continue;
            if ("单注".equals(technology.getZsgy())) {
                record.setInjectType(DAN_ZHU);
            }else if ("分注".equals(technology.getZsgy())) {
                Integer planSection = record.getPlanSection();
                // 如果水嘴包含方停，则需要减去
                planSection = planSection - stopWellNames.get(record.getWellname()).size();
                if (planSection == 1) {
                    record.setInjectType(FEN_ZHU1);
                }else if (planSection == 2) {
                    // 判断同心双管
                    if (technology.getTxsg()) {
                        record.setInjectType(FEN_ZHU2_TONG_XIN);
                    }else {
                        record.setInjectType(FEN_ZHU2);
                    }
                }else if (planSection == 3) {
                    record.setInjectType(FEN_ZHU3);
                }else if (planSection == 4) {
                    record.setInjectType(FEN_ZHU4);
                }else if (planSection == 5) {
                    record.setInjectType(FEN_ZHU5);
                }else if (planSection == 6) {
                    record.setInjectType(FEN_ZHU6);
                }else if (planSection == 7) {
                    record.setInjectType(FEN_ZHU7);
                }
            }
        }
        list = list.stream().filter(item -> StringUtils.isNotEmpty(item.getInjectType())).collect(Collectors.toList());
        if (list.size() > 0) {
            // 每批commit的个数
            int batchCount = 500;
            int index = 0;
            do {
                int batchLastIndex = Math.min(index + batchCount, list.size());
                List<WellSectionDaily> tmp = list.subList(index, batchLastIndex);
                wellSectionDailyDao.updateInjectType(tmp);
                index = index + batchCount;
            } while (index < list.size());
        }
    }

    /**
     * 注水层段日度数据汇总到月数据
     */
    @SneakyThrows
    @Transactional
    public void summaryWellSectionMonth(String month) {
        DateRange dateRange;
        if (month == null || "".equals(month)) {
            dateRange = DateUtils.getLastMonth(new Date());
            month = dateRange.getName();
        }else {
            dateRange = DateUtils.getMonthRange(DateUtils.parseDate(month, "yyyyMM"));
        }
        // 先删除
        wellSectionMonthDao.deleteByMonth(month);
        List<WellSectionMonth> list = calcWellSection(null, dateRange);
        // 入库
        if (list.size() > 0) {
            // 每批commit的个数
            int batchCount = 1;
            int index = 0;
            do {
                int batchLastIndex = Math.min(index + batchCount, list.size());
                List<WellSectionMonth> tmp = list.subList(index, batchLastIndex);
                wellSectionMonthDao.insertBatch(tmp);
                index = index + batchCount;
            } while (index < list.size());
        }
    }

    /**
     * 计算日度时间段的层段数据
     */
    public List<WellSectionMonth> calcWellSectionDaily(WellSectionMonthParam param) {
        if ("30200000".equals(param.getUnitcode())) {
            param.setUnitcode(null);
        }
        List<WellSectionMonth> result = new ArrayList<>();
        DateRange dateRange = new DateRange(param.getStartDate(), param.getEndDate(), "", DataType.daily);
        List<WellSectionMonth> list = calcWellSection(param.getUnitcode(), dateRange);
        // 入库
        if (list.size() > 0) {
            String tmpId = UuidUtils.generate();
            list.forEach(item -> item.setTmpId(tmpId));
            // 每批commit的个数
            int batchCount = 100;
            int index = 0;
            do {
                int batchLastIndex = Math.min(index + batchCount, list.size());
                List<WellSectionMonth> tmp = list.subList(index, batchLastIndex);
                wellSectionMonthDao.insertBatchTmp(tmp);
                index = index + batchCount;
            } while (index < list.size());
            param.setTmpId(tmpId);
            result = wellSectionMonthDao.selectListTmp(param);
            result.forEach(item -> {
                item.setStartDate(param.getStartDate());
                item.setEndDate(param.getEndDate());
            });
            // 删除临时表的数据
//            wellSectionMonthDao.deleteTmp(tmpId);
        }
        return result;
    }

    public List<WellSectionMonth> calcWellSection(String unitcode, DateRange dateRange) {
        // 先查询层段的最后一条数据，作为基础数据
        List<WellSectionMonth> list = dataSyncDao.selectWellSectionMonthBasic(unitcode, dateRange);

        // 查询单井数据
        List<WellSectionMonth> wellList = dataSyncDao.summaryByWell(unitcode, dateRange);
        Map<String, WellSectionMonth> wellMap = wellList.stream().collect(Collectors.toMap(WellSectionMonth::getWellname, v -> v));

        // 查询层段数据
        List<WellSectionMonth> sectionList = dataSyncDao.summaryWellSectionMonth(unitcode, dateRange);
        Map<String, WellSectionMonth> sectionMap = sectionList.stream().collect(Collectors.toMap(this::getKey, v -> v));

        // 分析评价 开始
        for (WellSectionMonth record : list) {
            // 是否判断出结果
            boolean hasResult = false;
            // 首先判断单井信息
            WellSectionMonth wellInfo = wellMap.get(record.getWellname());
            record.setSectionOpen(wellInfo.getSectionOpen());
            record.setWaterWellClassify(wellInfo.getWaterWellClassify());
            record.setRemarkNoCheck(wellInfo.getRemarkNoCheck());
            // 判断开井，逻辑见sql(生产时间大于等于24h且月累计注水量大于0.5为开井)
            if (!wellInfo.getSectionOpen()) {
                // 如果是关井，分析评价为空
                record.setEvaluate(null);
                record.setEvaluateBasis("不检查井：关井，生产时间大于等于24h且月累计注水量大于0为开井");
                hasResult = true;
            }

            // 判断是否为不检查井，不检查井的所有层都是不检查层
            // 不检查井：注水时间（月度累计值）：＜7*24h
            if (!hasResult && wellInfo.getDayNum() != null && wellInfo.getDayNum() < 7) {
                record.setEvaluate(NO_CHECK);
                record.setEvaluateBasis("不检查井：注水时间（月度累计值）：＜7*24h");
                hasResult = true;
            }
            // 不检查井：判断备注
            if (!hasResult && wellInfo.getRemarkNoCheck() != null && wellInfo.getRemarkNoCheck()) {
                record.setEvaluate(NO_CHECK);
                record.setEvaluateBasis("不检查井：备注原因");
                hasResult = true;
            }
            // 不检查层：方停且日注水量=0或者空
            if (!hasResult && record.getNozzle() != null && record.getNozzle().contains("方停")
                    && (record.getDailyWater() == null || record.getDailyWater().compareTo(BigDecimal.ZERO) == 0)) {
                record.setEvaluate(NO_CHECK);
                record.setEvaluateBasis("不检查层：方停且日注水量=0或者空");
                hasResult = true;
            }

            // 注水工艺和配注变化统计
            WellSectionMonth sectionInfo = sectionMap.get(this.getKey(record));
            if (sectionInfo != null) {
                record.setPp(sectionInfo.getPp());
                record.setPc(sectionInfo.getPc());
                record.setPt(sectionInfo.getPt());
                record.setPlanDailyWater(sectionInfo.getPlanDailyWater());
                record.setMonthWater(sectionInfo.getMonthWater());
                record.setDayNum(sectionInfo.getDayNum());
                record.setDailyWater(sectionInfo.getDailyWater());
                record.setDailyAbility(sectionInfo.getDailyAbility());
                if (!hasResult && sectionInfo.getDayNum() != null && sectionInfo.getDayNum() < 7) {
                    record.setEvaluate(NO_CHECK);
                    record.setEvaluateBasis("不检查层：注水时间：＜7*24h");
                    hasResult = true;
                }
            }

            // 计算（月注水量/注水时间）/日配注量
            Double rate = null;
            if (record.getDailyAbility() != null
                    && record.getPlanDailyWater() != null
                    && record.getPlanDailyWater().compareTo(BigDecimal.ZERO) > 0) {
                rate = record.getDailyAbility().divide(record.getPlanDailyWater(), 2, RoundingMode.HALF_UP).doubleValue();
            }
            // 计算差值
            if (record.getDailyAbility() != null && record.getPlanDailyWater() != null) {
                record.setDiffWater(record.getDailyAbility().subtract(record.getPlanDailyWater()));
            }

            // 如果有计算结果，则不继续计算
            if (hasResult) continue;

            /*  合格层
             * (1) 80%≤（月注水量/注水时间）/日配注量≤120%
             * (2) 月注水量为0且（配注为0或动停）
             */
            if ((rate != null && rate >= 0.8 && rate <= 1.2)) {
                record.setEvaluate(NORMAL);
                record.setEvaluateBasis("80%≤（月注水量/注水时间）/日配注量≤120%");
                continue;
            }
            if (record.getMonthWater() != null && record.getMonthWater().compareTo(BigDecimal.ZERO) == 0
                    && ((record.getPlanDailyWater() != null && record.getPlanDailyWater().compareTo(BigDecimal.ZERO) == 0)
                    || (record.getNozzle() != null && record.getNozzle().contains("动停")))) {
                record.setEvaluate(NORMAL);
                record.setEvaluateBasis("月注水量为0且（配注为0或动停）");
                continue;
            }

            /*  欠注层
             * （月注水量/注水时间）/日配注量＜80%
             */
            if (rate != null && rate < 0.8) {
                record.setEvaluate(LESS);
                record.setEvaluateBasis("（月注水量/注水时间）/日配注量＜80%");
                // 欠注类型
                if (record.getNozzle() != null && record.getNozzle().contains("控制")) {
                    record.setLessType(LESS_TYPE_NOZZLE);
                }
                // 除了带嘴欠注，都是放大
                else {
                    record.setLessType(LESS_TYPE_BIG);
                }
                continue;
            }

            /*  超注层
             * （1）分注井且配注：动停、月注水量：＞0
             * （2）（月注水量/注水时间）/日配注量＞120%
             */
            if (!"DAN_ZHU".equals(record.getInjectType()) // DAN_ZHU为单注
                    && record.getNozzle() != null && record.getNozzle().contains("动停")
                    && record.getMonthWater() != null
                    && record.getMonthWater().compareTo(BigDecimal.ZERO) > 0) {
                record.setEvaluate(MORE);
                record.setEvaluateBasis("分注井且配注：动停、月注水量：＞0");
                continue;
            }
            if (rate != null && rate > 1.2) {
                record.setEvaluate(MORE);
                record.setEvaluateBasis("（月注水量/注水时间）/日配注量＞120%");
                continue;
            }
            // 不清井
            // 分注井，有分层，无分层数据（注水层位）且日注水量为空
//            if (!"DAN_ZHU".equals(record.getInjectType())
//                    && StringUtils.isEmpty(record.getLayer())
//                    && record.getDailyWater() == null) {
//                record.setEvaluate(UNCLEAR);
//            }
            record.setEvaluate(UNCLEAR);
        }
        // 分析评价 结束
        return list;
    }

    private String getKey(WellSectionMonth item) {
        return item.getWellname() + "_" + item.getMonth() + "_" + item.getSection();
    }

    public void summaryMonth(String month) {
        log.info("月度数据汇总任务开始");
        this.summaryWellSectionMonth(month);
        sectionRateSummaryService.summary(month);
        unitMonthService.syncUnitMonth(month);
        log.info("月度数据汇总任务结束");
    }
}
