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

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
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.plugins.pagination.Page;
import ognl.IntHashMap;
import org.jeecg.common.util.UUIDGenerator;
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.SubwaySection;
import org.jeecg.modules.subwayNetwork.mapper.LightRailMapper;
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;

    @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())) {
            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().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.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.setRailOrderNum(i + 1);
            railManagement.setCreateBy("系统生成");
            railManagement.setUpdateBy("系统生成");
        }

        this.calcSection(lightRailId, xdkId, downRailList);

        allRailList.addAll(downRailList);

        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(lineAliasId);
        BigDecimal lineStartMileage = BigDecimal.ZERO;
        BigDecimal endMileage = lightRail.getUpLineMileage();

        // 3.2 循环处理
        int size = lineSpecialRailList.size();
        for (int i = 0; i < size; i++) {
            Map<String, Object> currentMap = lineSpecialRailList.get(i);
            BigDecimal currentStartMileage = Convert.toBigDecimal(currentMap.get("startMileage"));

            // 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);
                }
                continue;
            }


            // 3.2.2 后一个的开始 - 前一个的结束时间 > 0 相当于有空白
            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);
            }


            // 3.2.3 最后一次循环
            if (i == size - 1) {
                if (endMileage.subtract(currentStartMileage).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 lineAliasId) {
        return this.baseMapper.getLineSpecialRail(lineAliasId);
    }
}
