package org.jeecg.modules.deviceAsset.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.config.AsyncTask;
import org.jeecg.modules.deviceAsset.dto.RailManagementDTO;
import org.jeecg.modules.deviceAsset.entity.RailManagement;
import org.jeecg.modules.deviceAsset.mapper.RailManagementMapper;
import org.jeecg.modules.deviceAsset.service.IRailManagementService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.deviceAsset.vo.RailManagementVO;
import org.jeecg.modules.subwayNetwork.entity.LightRail;
import org.jeecg.modules.subwayNetwork.entity.LineAlias;
import org.jeecg.modules.subwayNetwork.entity.SubwaySection;
import org.jeecg.modules.subwayNetwork.mapper.LightRailMapper;
import org.jeecg.modules.subwayNetwork.mapper.LineAliasMapper;
import org.jeecg.modules.subwayNetwork.mapper.SubwaySectionMapper;
import org.jeecg.modules.utils.UnitCodeUtil;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 资产管理-钢轨管理 服务实现类
 * </p>
 *
 * @author hkl
 * @since 2023-07-06
 */
@Service
public class RailManagementServiceImpl extends ServiceImpl<RailManagementMapper, RailManagement> implements IRailManagementService {

    /**
     * 钢轨单元长度
     */
    public static BigDecimal UNIT_LENGTH = new BigDecimal("25");

    @Resource
    private LightRailMapper lightRailMapper;

    @Resource
    private SubwaySectionMapper subwaySectionMapper;

    @Resource
    private LineAliasMapper lineAliasMapper;

    @Resource
    private AsyncTask asyncTask;

    @Override
    public Page<RailManagementVO> queryPageList(Page<RailManagementVO> pageData, RailManagementDTO dto) {
        return this.baseMapper.queryPageList(pageData, dto);
    }

    @Override
    public void edit(RailManagement railManagement) {
        if (ObjectUtil.isEmpty(railManagement.getId())) {
            railManagement.setId(UUIDGenerator.generate());
            String utilCode = UnitCodeUtil.railUnitCodeUtil(railManagement.getLineAliasId());
            railManagement.setUnitCode(utilCode);

            this.save(railManagement);
        } else {
            this.updateById(railManagement);
        }
    }

    // 1.判断完整的线路有没有空白部分（指剩余区间既不是道岔、曲线、竖曲线、钢轨的部分），只需要填空白部分，空白部分一定是钢轨，按照25一根的逻辑余数自成一根；
    // 2.如果不存在空白部分，则定义道岔曲线竖曲线为绝对正确里程值，并且定义为特殊钢轨，相邻两个特殊钢轨之间的里程区间按照25一根的逻辑余数自成一根。

    @Override
    public void intelligentGeneration(String lightRailId) {
        // 1.删除整条线的
        this.lambdaUpdate().eq(RailManagement::getLightRailId, lightRailId).remove();


        // 2.查询当前车站的上下行里程
        LightRail lightRail = lightRailMapper.selectById(lightRailId);


        // 3.处理上行
        // 3.1 查询上行所有里程数
        List<RailManagement> allRailList = new ArrayList<>();
        String sdkId = "1"; // 上行线id
        generationCore(lightRail, allRailList, sdkId);

        for (int i = 0; i < allRailList.size(); i++) {
            RailManagement railManagement = allRailList.get(i);
            String railCode = "钢轨[上行]" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setRailCode(railCode);
            String unitCode = "SXXGG" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setUnitCode(unitCode);
            railManagement.setLightRailId(lightRailId);
            railManagement.setRailOrderNum(i + 1);
            railManagement.setCreateBy("系统生成");
            railManagement.setUpdateBy("系统生成");
        }
        // 3.2 计算区间
        this.calcSection(lightRailId, sdkId, allRailList);


        // 4.处理下行
        List<RailManagement> downRailList = new ArrayList<>();
        String xdkId = "2"; // 下行线id
        generationCore(lightRail, downRailList, xdkId);

        for (int i = 0; i < downRailList.size(); i++) {
            RailManagement railManagement = downRailList.get(i);
            String railCode = "钢轨[下行]" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setRailCode(railCode);
            String unitCode = "DXXGG" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setUnitCode(unitCode);
            railManagement.setLightRailId(lightRailId);
            railManagement.setRailOrderNum(i + 1);
            railManagement.setCreateBy("系统生成");
            railManagement.setUpdateBy("系统生成");
        }

        this.calcSection(lightRailId, xdkId, downRailList);

        allRailList.addAll(downRailList);

        // 异步执行保存
        asyncTask.getAsyncExecutor().execute(() -> {
            this.saveBatch(allRailList);
        });

    }

    @Override
    public void intelligentGeneration(String lightRailId, String lineAliasId) {
        System.out.printf("lineAliasId=" + lineAliasId);
        // 2.查询当前车站的上下行里程
        LightRail lightRail = lightRailMapper.selectById(lightRailId);

        // 3.1 查询上行所有里程数
        List<RailManagement> allRailList = new ArrayList<>();
        generationCore(lightRail, allRailList, lineAliasId);

        for (int i = 0; i < allRailList.size(); i++) {
            RailManagement railManagement = allRailList.get(i);
            String railCode = "钢轨[上行]" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setRailCode(railCode);
            String unitCode = "SXXGG" + UnitCodeUtil.supplementZero(4, i + 1);
            railManagement.setUnitCode(unitCode);
            railManagement.setLightRailId(lightRailId);
            railManagement.setRailOrderNum(i + 1);
            railManagement.setCreateBy("系统生成");
            railManagement.setUpdateBy("系统生成");
        }
        // 3.2 计算区间
        this.calcSection(lightRailId, lineAliasId, allRailList);

        // 异步执行保存
        asyncTask.getAsyncExecutor().execute(() -> {
            this.saveBatch(allRailList);
        });

    }

    /**
     * 计算区间
     *
     * @param allRailList
     */
    private void calcSection(String lightRailId, String lineAliasId, List<RailManagement> allRailList) {
        // 查询该线路下面所有的区间
        LambdaQueryWrapper<SubwaySection> subwaySectionQw = Wrappers.lambdaQuery();
        subwaySectionQw.eq(SubwaySection::getLightRailId, lightRailId)
                .eq(SubwaySection::getLineAliasId, lineAliasId);
        List<SubwaySection> subwaySections = subwaySectionMapper.selectList(subwaySectionQw);


        // 计算单元格归属
        Map<String, SubwaySection> optimalSolutionMap = new HashMap<>();
        for (RailManagement railManagement : allRailList) {

            for (SubwaySection subwaySection : subwaySections) {
                // 如果钢轨单元的中心里程属于区间，则钢轨单元属于这个区间
                BigDecimal centerMileage = railManagement.getCenterMileage();

                if (subwaySection.getSectionStartingMileage().compareTo(centerMileage) <= 0 &&
                        subwaySection.getSectionEndMileage().compareTo(centerMileage) > 0) {

                    // 用来判断区间是不是最小区间,最优解
                    SubwaySection optimalSolution = optimalSolutionMap.get(railManagement.getId());
                    if (null == optimalSolution) {
                        optimalSolutionMap.put(railManagement.getId(), subwaySection);
                    } else {

                        // 检查第一个区间的端点是否在第二个区间内
                        boolean startInRange = subwaySection.getSectionStartingMileage().compareTo(optimalSolution.getSectionStartingMileage()) >= 0
                                && subwaySection.getSectionStartingMileage().compareTo(optimalSolution.getSectionEndMileage()) <= 0;
                        boolean endInRange = subwaySection.getSectionEndMileage().compareTo(optimalSolution.getSectionStartingMileage()) >= 0
                                && subwaySection.getSectionEndMileage().compareTo(optimalSolution.getSectionEndMileage()) <= 0;

                        if (startInRange && endInRange) {
                            optimalSolutionMap.put(railManagement.getId(), subwaySection);
                        }
                    }

                }
            }

            SubwaySection optimalSolution = optimalSolutionMap.get(railManagement.getId());
            if (optimalSolution != null) {
                railManagement.setSectionId(optimalSolution.getId());
            }
            optimalSolutionMap.remove(railManagement.getId());
        }


    }


    /**
     * 生成核心
     *
     * @param lightRail
     * @param allRailList
     * @param lineAliasId
     */
    private void generationCore(LightRail lightRail, List<RailManagement> allRailList, String lineAliasId) {
        List<Map<String, Object>> lineSpecialRailList = this.getLineSpecialRail(lightRail.getId(), lineAliasId);
        BigDecimal lineStartMileage = BigDecimal.ZERO;
        LineAlias lineAlias = lineAliasMapper.selectById(lineAliasId);
        BigDecimal endMileage = lightRail.getUpLineMileage();
        if (lineAlias.getLineAliasName().contains("下行")) {
            endMileage = lightRail.getDownLineMileage();
        }
        int size = lineSpecialRailList.size();

        // 1.如果查询不到曲线，竖曲线，道岔，则全是钢轨
        if (size == 0 && endMileage.compareTo(lineStartMileage) > 0) {

            List<RailManagement> innerRailList = this.generate(lineStartMileage, endMileage, lineAliasId);
            allRailList.addAll(innerRailList);

        } else {
            for (int i = 0; i < size; i++) {
                Map<String, Object> currentMap = lineSpecialRailList.get(i);
                BigDecimal currentStartMileage = Convert.toBigDecimal(currentMap.get("startMileage"));
                BigDecimal currentEndMileage = Convert.toBigDecimal(currentMap.get("endMileage"));
                // 3.2.1 第一次进入循环
                if (i == 0) {
                    if (currentStartMileage.subtract(lineStartMileage).compareTo(BigDecimal.ZERO) > 0) {
                        List<RailManagement> innerRailList = this.generate(lineStartMileage, currentStartMileage, lineAliasId);
                        allRailList.addAll(innerRailList);
                    }
                    // 只有一个的情况下要继续向下执行
                    if (size != 1) {
                        continue;
                    }
                }


                // 3.2.2 后一个的开始里程 - 前一个的结束里程 > 0 相当于有空白[注：1个单元情况下不做]
                if (0 != size - 1) {
                    Map<String, Object> frontMap = lineSpecialRailList.get(i - 1);
                    BigDecimal frontEndMileage = Convert.toBigDecimal(frontMap.get("endMileage"));
                    if (currentStartMileage.subtract(frontEndMileage).compareTo(BigDecimal.ZERO) > 0) {
                        List<RailManagement> innerRailList = this.generate(frontEndMileage, currentStartMileage, lineAliasId);
                        allRailList.addAll(innerRailList);
                    }
                }


                if (i == size - 1) {
                    // 3.2.3 最后一次循环
                    // ① 线路终点里程 > 最后一个单元结束里程,要补充[最后一个单元结束里程,线路终点里程]
                    if (endMileage.subtract(currentEndMileage).compareTo(BigDecimal.ZERO) > 0) {
                        List<RailManagement> innerRailList = this.generate(currentEndMileage, endMileage, lineAliasId);
                        allRailList.addAll(innerRailList);
                    }
                    // ② 最后一个单元起点里程 < 线路终点里程 < 最后一个单元结束里程,补充[前一个终点,最后一个单元起点里程]
                    if (endMileage.subtract(currentStartMileage).compareTo(BigDecimal.ZERO) > 0 && endMileage.subtract(currentEndMileage).compareTo(BigDecimal.ZERO) < 0) {
                        List<RailManagement> innerRailList = this.generate(currentStartMileage, endMileage, lineAliasId);
                        allRailList.addAll(innerRailList);
                    }

                    // ③ 最后一个单元起点里程 > 线路终点里程 啥都不做
                }


            }
        }

    }


    /**
     * @param startMileage
     * @param endMileage
     * @param lineAliasId
     * @return
     */
    private List<RailManagement> generate(BigDecimal startMileage, BigDecimal endMileage, String lineAliasId) {
        List<RailManagement> result = new ArrayList<>();

        // 1.处理25米一段的钢轨
        while (startMileage.add(UNIT_LENGTH).compareTo(endMileage) < 0) {
            // 开始里程向后移动25米
            BigDecimal currentEndMileage = startMileage.add(UNIT_LENGTH);

            // 中心里程 = (开始里程+结束里程) / 2
            BigDecimal centerMileage = startMileage.add(currentEndMileage).divide(new BigDecimal("2"), 3, RoundingMode.HALF_UP);


            RailManagement railManagement = new RailManagement();
            railManagement.setId(UUIDGenerator.generate());
            railManagement.setLineAliasId(lineAliasId);
            railManagement.setStartingMileage(startMileage);
            railManagement.setCenterMileage(centerMileage);
            railManagement.setEndMileage(currentEndMileage);
            result.add(railManagement);

            startMileage = currentEndMileage;
        }


        // 2.处理不到25米一段的钢轨
        RailManagement railManagement = new RailManagement();
        railManagement.setId(UUIDGenerator.generate());
        railManagement.setLineAliasId(lineAliasId);
        railManagement.setStartingMileage(startMileage);
        railManagement.setCenterMileage(startMileage.add(endMileage).divide(new BigDecimal("2"), 3, RoundingMode.HALF_UP));  // 中心里程 = (开始里程+结束里程) / 2
        railManagement.setEndMileage(endMileage);
        result.add(railManagement);
        return result;
    }


    @Override
    public List<Map<String, Object>> getLineSpecialRail(String lightRailId, String lineAliasId) {
        return this.baseMapper.getLineSpecialRail(lightRailId, lineAliasId);
    }

    @Override
    public Long checkRailCodeRepeat(String id, String lightRailId, String railCode) {
        return this.baseMapper.checkRailCodeRepeat(id, lightRailId, railCode);
    }

    @Override
    public Map<String, Object> getAddParams(String lightRailId, String lineAliasId, String sectionId) {
        Map<String, Object> map = new HashMap<>();
       /* List<Map<String, Object>> lineSpecialRailList = this.getLineSpecialRail(lightRailId, lineAliasId);

        // 过滤出命中区间
        List<Map<String, Object>> sectionMapList = new ArrayList<>();
        for (Map<String, Object> lineSpecialRaiMap : lineSpecialRailList) {
            String currentSectionId = Convert.toStr(lineSpecialRaiMap.get("sectionId"));
            if (sectionId.equals(currentSectionId)) {
                sectionMapList.add(lineSpecialRaiMap);
            }
        }
        SubwaySection subwaySection = subwaySectionMapper.selectById(sectionId);
        BigDecimal subwayStartMileage = subwaySection.getSectionStartingMileage();
        BigDecimal subwayEndMileage = subwaySection.getSectionEndMileage();

        if (ObjectUtil.isNotEmpty(sectionMapList)) {
            int size = sectionMapList.size();


            for (int i = 0; i < size; i++) {
                Map<String, Object> sectionMap = sectionMapList.get(i);
                BigDecimal currentStartMileage = Convert.toBigDecimal(sectionMap.get("startMileage"));
                BigDecimal currentEndMileage = Convert.toBigDecimal(sectionMap.get("endMileage"));


                // 计算开始空白开始里程
                // 单元起始里程-区间起始里程 > 0 说明有空
                if (currentStartMileage.subtract(subwayStartMileage).compareTo(BigDecimal.ZERO) > 0) {
                    // 有空白地方,取 区间起点= 这个单元起点
                    subwayEndMileage = currentStartMileage;


                    // 计算结束里程
//                    if (currentEndMileage.compareTo(subwayEndMileage) < 0) {
//                        subwayEndMileage = currentStartMileage;
//                    }
//                    System.out.println("subwayStartMileage=" + subwayStartMileage);

                    break;

                } else {
                    // 没有空白则像后面移动,并结束本次循环
                    subwayStartMileage = currentEndMileage;
                    continue;
                }


            }

        }*/

        SubwaySection subwaySection = subwaySectionMapper.selectById(sectionId);
        BigDecimal subwayStartMileage = subwaySection.getSectionStartingMileage();
        BigDecimal subwayEndMileage = subwaySection.getSectionEndMileage();

        map.put("startMileage", subwayStartMileage);
        map.put("endMileage", subwayEndMileage);
        return map;
    }
}
