package com.aps.service.plan;

import com.aps.common.util.DateGroupUtil;
import com.aps.entity.Algorithm.OrderSortRule;
import com.aps.entity.ProdSceneConfig;
import com.aps.entity.StrategyScheduling;
import com.aps.entity.basic.Order;
import com.aps.service.ProdSceneConfigService;
import com.aps.service.UserStrategyRuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 排产策略服务：负责读取当前排产要使用的策略，并把策略转换成订单排序规则。
 */
@Slf4j
@Service
public class ScheduleStrategyService {

    @Autowired
    private UserStrategyRuleService userStrategyRuleService;

    @Autowired
    private ProdSceneConfigService prodSceneConfigService;

    /**
     * 获取本次排产实际使用的用户。
     * 前端传 userId 时直接使用；没传时从场景创建人 createUser 反查。
     */
    public Long resolveScheduleUserId(String sceneId, Long userId) {
        if (userId != null) {
            return userId;
        }
        try {
            ProdSceneConfig sceneConfig = prodSceneConfigService == null ? null : prodSceneConfigService.getById(sceneId);
            return parseLongSafely(sceneConfig == null ? null : sceneConfig.getCreateUser());
        } catch (Exception e) {
            log.warn("读取场景用户失败，sceneId={}", sceneId, e);
            return null;
        }
    }

    /**
     * 读取 /userStrategyRule/save 保存的用户策略；没有用户策略时由 UserStrategyRuleService 兜底全局策略。
     */
    public List<StrategyScheduling> loadEffectiveForwardScheduling(Long userId, Long baseRuleId, String sceneId, String userRuleId) {
        try {
            List<StrategyScheduling> schedulings =
                    userStrategyRuleService.getEffectiveForwardScheduling(userId, baseRuleId, sceneId, userRuleId);
            return schedulings == null ? Collections.emptyList() : schedulings;
        } catch (Exception e) {
            log.warn("读取排产策略失败，使用默认优先级排序，sceneId={}, userId={}, baseRuleId={}, userRuleId={}",
                    sceneId, userId, baseRuleId, userRuleId, e);
            return Collections.emptyList();
        }
    }

    public Object loadEffectiveKpiConfig(Long userId, Long baseRuleId, String sceneId, String userRuleId) {
        try {
            Map<String, Object> params = new HashMap<>();
            Long effectiveUserId = resolveScheduleUserId(sceneId, userId);
            if (effectiveUserId != null) {
                params.put("userId", effectiveUserId);
            }
            if (baseRuleId != null) {
                params.put("baseRuleId", baseRuleId);
            }
            if (userRuleId != null && !userRuleId.trim().isEmpty()) {
                params.put("userRuleId", userRuleId);
            }

            Map<String, Object> effectiveRule = userStrategyRuleService.getEffectiveRule(params);
            return effectiveRule == null ? null : effectiveRule.get("kpiConfig");
        } catch (Exception e) {
            log.warn("Load KPI strategy failed, use GlobalParam default KPI. sceneId={}, userId={}, baseRuleId={}, userRuleId={}",
                    sceneId, userId, baseRuleId, userRuleId, e);
            return null;
        }
    }

    public boolean loadEffectiveIsJit(Long userId, Long baseRuleId, String sceneId, String userRuleId) {
        try {
            Map<String, Object> params = new HashMap<>();
            Long effectiveUserId = resolveScheduleUserId(sceneId, userId);
            if (effectiveUserId != null) {
                params.put("userId", effectiveUserId);
            }
            if (baseRuleId != null) {
                params.put("baseRuleId", baseRuleId);
            }
            if (userRuleId != null && !userRuleId.trim().isEmpty()) {
                params.put("userRuleId", userRuleId);
            }

            Map<String, Object> effectiveRule = userStrategyRuleService.getEffectiveRule(params);
            return effectiveRule != null && !asBoolean(effectiveRule.get("isjit"), true);
        } catch (Exception e) {
            log.warn("Load JIT strategy failed, use GlobalParam default isJit=false. sceneId={}, userId={}, baseRuleId={}, userRuleId={}",
                    sceneId, userId, baseRuleId, userRuleId, e);
            return false;
        }
    }

    public boolean loadEffectiveIsOptimizer(Long userId, Long baseRuleId, String sceneId, String userRuleId) {
        try {
            Map<String, Object> params = new HashMap<>();
            Long effectiveUserId = resolveScheduleUserId(sceneId, userId);
            if (effectiveUserId != null) {
                params.put("userId", effectiveUserId);
            }
            if (baseRuleId != null) {
                params.put("baseRuleId", baseRuleId);
            }
            if (userRuleId != null && !userRuleId.trim().isEmpty()) {
                params.put("userRuleId", userRuleId);
            }

            Map<String, Object> effectiveRule = userStrategyRuleService.getEffectiveRule(params);
            return effectiveRule == null || asBoolean(effectiveRule.get("isOptimizer"), true);
        } catch (Exception e) {
            log.warn("Load optimizer strategy failed, use GlobalParam default isOptimizer=true. sceneId={}, userId={}, baseRuleId={}, userRuleId={}",
                    sceneId, userId, baseRuleId, userRuleId, e);
            return true;
        }
    }

    public OrderSortRule createMultiConditionRule(List<Order> orders) {
        return createMultiConditionRule(orders, Collections.emptyList());
    }

    /**
     * 把 forwardScheduling 中 value=true 的策略项按 sort 顺序转换成 OrderSortRule。
     * 如果用户策略和全局策略都没有可用项，则回退到原来的 priority 升序。
     */
    public OrderSortRule createMultiConditionRule(List<Order> orders, List<StrategyScheduling> strategySchedulings) {
        OrderSortRule rule = new OrderSortRule();
        rule.setEnabled(true);
        List<OrderSortRule.SortCondition> conditions = new ArrayList<>();

        try {
            Set<String> fields = new HashSet<>();
            List<StrategyScheduling> selecteds = strategySchedulings == null
                    ? Collections.emptyList()
                    : strategySchedulings.stream()
                    .filter(StrategyScheduling::isValue)
                    .sorted(Comparator.comparingInt(StrategyScheduling::getSort))
                    .collect(Collectors.toList());

            int sequence = 1;
            for (StrategyScheduling strategy : selecteds) {
                OrderSortRule.SortCondition condition = buildSortConditionFromStrategy(orders, strategy, sequence, fields);
                if (condition != null) {
                    conditions.add(condition);
                    fields.add(condition.getFieldName());
                    sequence++;
                }
            }
        } catch (Exception e) {
            log.warn("策略排序条件生成失败，使用默认优先级排序", e);
            conditions.clear();
        }

        if (conditions.isEmpty()) {
            conditions.add(createSortCondition(1, "priority", false));
        }

        rule.setConditions(conditions);
        return rule;
    }

    /**
     * 单个策略项到排序字段的映射。
     * 例如 deliveryDate -> dueDate/groupDueDate，startDate -> startDate/groupStartDate。
     */
    private OrderSortRule.SortCondition buildSortConditionFromStrategy(
            List<Order> orders,
            StrategyScheduling strategy,
            int sequence,
            Set<String> fields) throws Exception {
        if (strategy == null || strategy.getName() == null) {
            return null;
        }

        String name = normalizeStrategyName(strategy.getName());
        int amplitude = strategy.getAmplitude();
        switch (name) {
            case "customerduedate":
            case "customerdue_date":
            case "customer_due_date":
            case "deliverydate":
            case "delivery_date":
            case "duedate":
            case "due_date": {
                String fieldName = "dueDate";
                // amplitude > 0 表示按 N 天跨度分组排序；amplitude <= 0 表示直接按真实交期排序。
                if (amplitude > 0) {
                    DateGroupUtil.calculateGroupDueDate(orders, "dueDate", "groupDueDate", amplitude);
                    fieldName = "groupDueDate";
                }
                return createSortCondition(sequence, fieldName, false);
            }
            case "startddate":
            case "startd_date":
            case "startdate":
            case "start_date": {
                String fieldName = "startDate";
                // 开始日期策略同样支持按 amplitude 天数分组。
                if (amplitude > 0) {
                    DateGroupUtil.calculateGroupDueDate(orders, "startDate", "groupStartDate", amplitude);
                    fieldName = "groupStartDate";
                }
                return createSortCondition(sequence, fieldName, false);
            }
            case "gatheringseries":
            case "gathering_series":
            case "serie":
            case "series":
                return fields.contains("serie") ? null : createSortCondition(sequence, "serie", false);
            case "minimumwopriority":
            case "minimum_wo_priority":
            case "min_wo_priority":
            case "priority":
            case "priority_asc":
                return fields.contains("priority") ? null : createSortCondition(sequence, "priority", false);
            case "maximumwopriority":
            case "maximum_wo_priority":
            case "max_wo_priority":
            case "priority_desc":
                return fields.contains("priority") ? null : createSortCondition(sequence, "priority", true);
            case "materialrise":
            case "material_rise":
            case "materialcode":
            case "material_code":
                return fields.contains("materialCode") ? null : createSortCondition(sequence, "materialCode", false);
            case "planrise":
            case "plan_rise":
            case "ordercode_asc":
            case "order_code_asc":
                return fields.contains("orderCode") ? null : createSortCondition(sequence, "orderCode", false);
            case "plandrop":
            case "plan_drop":
            case "ordercode_desc":
            case "order_code_desc":
                return fields.contains("orderCode") ? null : createSortCondition(sequence, "orderCode", true);
            case "minimizetoolchangeovers":
            case "minimize_tool_changeovers":
            case "minimizechangeover":
            case "minimize_changeover":
                return fields.contains("minimize_changeover") ? null : createSortCondition(sequence, "minimize_changeover", false);
            default:
                log.warn("跳过不支持的排产策略项: {}", strategy.getName());
                return null;
        }
    }

    private Long parseLongSafely(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        try {
            return Long.valueOf(value.trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private String normalizeStrategyName(String name) {
        return name == null ? "" : name.trim().replace("-", "_").replace(" ", "_").toLowerCase(Locale.ROOT);
    }

    private OrderSortRule.SortCondition createSortCondition(int sequence, String fieldName, boolean reverse) {
        OrderSortRule.SortCondition condition = new OrderSortRule.SortCondition();
        condition.setSequence(sequence);
        condition.setFieldName(fieldName);
        condition.setReverse(reverse);
        return condition;
    }

    private boolean asBoolean(Object value, boolean defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue() != 0;
        }
        String text = String.valueOf(value).trim();
        if ("1".equals(text)) {
            return true;
        }
        if ("0".equals(text)) {
            return false;
        }
        return text.isEmpty() ? defaultValue : Boolean.parseBoolean(text);
    }
}
