package com.agri.system.util;

import com.agri.common.exception.ServiceException;

import com.agri.system.domain.SysAutoTerm;
import com.agri.system.domain.SysRollerParam;
import com.agri.system.domain.vo.AgriTermVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * 卷膜参数校验工具类（和前端 saveAutoTerm 1:1 对齐）
 */
public class RollerParamValidateUtil {
    // 条件数量上限（和前端 5 保持一致）
    private static final int MAX_TERM_COUNT = 5;

    /**
     * 核心校验方法：完全复刻前端 saveAutoTerm 逻辑
     * @param agriTerms 对应前端 termList
     * @param filmRollerList 对应前端 this.filmRollerList（卷膜名称列表：["卷膜1","卷膜2","卷膜3"]）
     */
    public static void validate(List<AgriTermVo> agriTerms, List<String> filmRollerList) {
        // 对应前端 termMap = this.termList
        List<AgriTermVo> termMap = agriTerms;
        // 对应前端 rollerList = []
        List<String> rollerList = new ArrayList<>();
        // 对应前端 showTips = null
        String showTips = null;

        // 1. 定义校验规则数组（完全复刻前端 checkRules）
        List<CheckRule> checkRules = buildCheckRules();

        // 2. 外层循环：遍历每个校验规则（对应前端 for (const [_, rule] of checkRules.entries())）
        for (CheckRule rule : checkRules) {
            // 内层循环：遍历每个卷膜（对应前端 for (const [index, item] of this.filmRollerList.entries())）
            for (int index = 0; index < filmRollerList.size(); index++) {
                String filmRoller = filmRollerList.get(index); // 卷膜名称：卷膜1/卷膜2/卷膜3
                // 对应前端 term = termMap[index]['terms']
                List<SysAutoTerm> term = termMap.get(index).getTerms();
                // 对应前端 rollerParam = termMap[index]['config']
                SysRollerParam rollerParam = termMap.get(index).getConfig();

                // 对应前端 if (!rollerParam) 逻辑
                if (rollerParam == null) {
                    throw new ServiceException("参数设置失败，请下拉刷新后重试！");
                }
                // 对应前端 else if (rule.validate(rollerParam, term)) 逻辑
                else if (rule.validate(rollerParam, term)) {
                    rollerList.add(filmRoller);
                    showTips = rule.getTip();
                }
            }

            // 对应前端 if (rollerList.length>0) 逻辑：校验失败则抛异常
            if (!rollerList.isEmpty()) {
                String errorMsg = String.format("【%s】%s", String.join("，", rollerList), showTips);
                throw new ServiceException(errorMsg);
            }
        }
    }

    /**
     * 构建校验规则数组（完全复刻前端 checkRules）
     */
    private static List<CheckRule> buildCheckRules() {
        List<CheckRule> rules = new ArrayList<>();

        // 规则1：请设置自动化条件后重新保存重试！
        rules.add(new CheckRule("请设置自动化条件后重新保存重试！", (rollerParam, term) ->
                // 前端：rollerParam.refTemp === '请选择' && !(term && term.length > 0)
                // Java 对应：refTempCode 为空（对应前端 '请选择'） + 条件为空
                StringUtils.isBlank(rollerParam.getRefTempCode()) && (CollectionUtils.isEmpty(term))
        ));

        // 规则2：参考温度未设置，请点击相应页签左上角设置后重试！
        rules.add(new CheckRule("参考温度未设置，请点击相应页签左上角设置后重试！", (rollerParam, term) ->
                // 前端：rollerParam.refTemp === '请选择'
                StringUtils.isBlank(rollerParam.getRefTempCode())
        ));

        // 规则3：计算风口总长和手动设置风口长度至少填写一个！
        rules.add(new CheckRule("计算风口总长和手动设置风口长度至少填写一个！请填写后重试！", (rollerParam, term) ->
                // 前端：!((manualTotalLen>0) || (autoTotalLen>0))
                !((rollerParam.getManualTotalLen() != null && rollerParam.getManualTotalLen().compareTo(BigDecimal.ZERO)>0)
                        || (rollerParam.getAutoTotalLen() != null && rollerParam.getAutoTotalLen().compareTo(BigDecimal.ZERO)>0))
        ));

        // 规则4：预留风口长度未设置！
        rules.add(new CheckRule("预留风口长度未设置，请点击相应页签右上角设置后重试！", (rollerParam, term) ->
                // 前端：!(reservedLen && reservedLen > 0)
                !(rollerParam.getReservedLen() != null && rollerParam.getReservedLen().compareTo(BigDecimal.ZERO) > 0)
        ));

        // 规则5：温度控制未设置！
        rules.add(new CheckRule("温度控制未设置，请设置后重新尝试！", (rollerParam, term) ->
                // 前端：!(term && term.length > 0)
                CollectionUtils.isEmpty(term)
        ));

        // 规则6：温度控制设置条数超过上限！
        rules.add(new CheckRule("温度控制设置条数超过上限！请调整后重试", (rollerParam, term) ->
                // 前端：term && term.length > 5
                !CollectionUtils.isEmpty(term) && term.size() > MAX_TERM_COUNT
        ));

        // 规则7：温度控制运行时间填写不完整！
        rules.add(new CheckRule("温度控制运行时间填写不完整，请检查填写后重新尝试！", (rollerParam, term) ->
                // 前端：term.some(item => !(item.startTime && item.startTime!=='请选择时间' && item.endTime && item.endTime !== '请选择时间'))
                !CollectionUtils.isEmpty(term) && term.stream().anyMatch(item ->
                        item.getStartTime() == null || item.getEndTime() == null
                )
        ));

        // 规则8：温度控制运行时间起不能大于止！
        rules.add(new CheckRule("温度控制运行时间起不能大于止，请检查填写后重新尝试！", (rollerParam, term) ->
                // 前端：term.some(item => (item.startTime > item.endTime))
                !CollectionUtils.isEmpty(term) && term.stream().anyMatch(item ->
                        item.getStartTime() != null && item.getEndTime() != null
                                && item.getStartTime().after(item.getEndTime())
                )
        ));

        // 规则9：温度控制运行时间存在冲突！
        rules.add(new CheckRule("温度控制运行时间存在冲突，请检查填写后重新尝试！", (rollerParam, term) ->
                // 前端：调用 checkTimeConflict(term) 返回 isConflict
                !CollectionUtils.isEmpty(term) && checkTimeConflict(term)
        ));

        // 规则10：温度控制适宜温度填写不完整！
        rules.add(new CheckRule("温度控制适宜温度填写不完整，请填写后重新尝试！", (rollerParam, term) ->
                // 前端：term.some(item => !(item.temp && item.temp!=='选择'))
                !CollectionUtils.isEmpty(term) && term.stream().anyMatch(item ->
                        item.getTemp() == null || item.getTemp().compareTo(BigDecimal.ZERO) <= 0
                )
        ));

        // 规则11：温度控制风口开合大小填写不完整！
        rules.add(new CheckRule("温度控制风口开合大小填写不完整，请填写后重新尝试！", (rollerParam, term) ->
                // 前端：term.some(item => !(item.vent && item.vent!=='选择'))
                !CollectionUtils.isEmpty(term) && term.stream().anyMatch(item ->
                        item.getVent() == null || item.getVent() <= 0
                )
        ));

        return rules;
    }

    /**
     * 时间冲突判断（完全复刻前端 checkTimeConflict 逻辑）
     */
    private static boolean checkTimeConflict(List<SysAutoTerm> term) {
        if (CollectionUtils.isEmpty(term) || term.size() <= 1) {
            return false;
        }

        // 遍历判断时间区间是否冲突
        for (int i = 0; i < term.size(); i++) {
            SysAutoTerm item1 = term.get(i);
            for (int j = i + 1; j < term.size(); j++) {
                SysAutoTerm item2 = term.get(j);
                // 前端时间冲突逻辑：判断两个时间区间是否重叠
                Date start1 = item1.getStartTime();
                Date end1 = item1.getEndTime();
                Date start2 = item2.getStartTime();
                Date end2 = item2.getEndTime();

                if (start1 == null || end1 == null || start2 == null || end2 == null) {
                    continue;
                }

                // 核心冲突判断逻辑（和前端一致）
                boolean isConflict = !(end1.before(start2) || start1.after(end2));
                if (isConflict) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 校验规则内部类（对应前端 checkRules 里的单个规则对象）
     */
    @FunctionalInterface
    interface ValidateFunction {
        boolean validate(SysRollerParam rollerParam, List<SysAutoTerm> term);
    }

    static class CheckRule {
        private final String tip; // 对应前端 rule.tip
        private final ValidateFunction validate; // 对应前端 rule.validate

        public CheckRule(String tip, ValidateFunction validate) {
            this.tip = tip;
            this.validate = validate;
        }

        public String getTip() {
            return tip;
        }

        public boolean validate(SysRollerParam rollerParam, List<SysAutoTerm> term) {
            return validate.validate(rollerParam, term);
        }
    }
}