package com.njcn.gather.steady.datavie.component;

import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 稳态趋势字段白名单解析器。
 */
@Component
@RequiredArgsConstructor
public class SteadyTrendFieldResolver {

    private static final int MAX_LINE_COUNT = 8;
    private static final int MAX_INDICATOR_COUNT = 8;
    private static final int MAX_SERIES_COUNT = 24;
    private static final int MAX_HARMONIC_ORDER_COUNT = 3;
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private final SteadyTrendIndicatorCatalog indicatorCatalog;

    public List<SteadyTrendResolvedFieldBO> resolveFields(SteadyTrendQueryParam param) {
        validateBasicParam(param);
        List<String> lineIds = normalizeTextList(param.getLineIds());
        List<String> indicatorCodes = normalizeTextList(param.getIndicatorCodes());
        List<String> statTypes = normalizeUpperList(param.getStatTypes());
        if (statTypes.isEmpty()) {
            statTypes.add("AVG");
        }
        List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
        for (String lineId : lineIds) {
            for (String indicatorCode : indicatorCodes) {
                SteadyTrendIndicatorDefinitionBO indicator = requireIndicator(indicatorCode);
                List<String> phases = resolvePhases(indicator);
                for (String phase : phases) {
                    for (String statType : statTypes) {
                        validateStatType(indicator, statType);
                        result.addAll(resolveIndicatorFields(lineId, indicator, phase, statType, param.getHarmonicOrders()));
                    }
                }
            }
        }
        if (result.size() > MAX_SERIES_COUNT) {
            throw fail("趋势曲线数量不能超过 24 条，请缩小监测点、指标或统计类型范围");
        }
        return result;
    }

    public LocalDateTime parseRequiredTime(String time, String emptyMessage) {
        String text = trimToNull(time);
        if (text == null) {
            throw fail(emptyMessage);
        }
        try {
            return LocalDateTime.parse(text, TIME_FORMATTER);
        } catch (DateTimeParseException ex) {
            throw fail("时间格式不正确，仅支持 yyyy-MM-dd HH:mm:ss");
        }
    }

    private List<SteadyTrendResolvedFieldBO> resolveIndicatorFields(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                                                    String phase, String statType, List<Integer> harmonicOrders) {
        if (Boolean.TRUE.equals(indicator.getHarmonic())) {
            return resolveHarmonicFields(lineId, indicator, phase, statType, harmonicOrders);
        }
        List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
        for (SteadyTrendSeriesFieldBO seriesField : indicator.getSeriesFields()) {
            result.add(buildResolvedField(lineId, indicator, phase, statType, seriesField.getField(), seriesField.getName()));
        }
        return result;
    }

    private List<SteadyTrendResolvedFieldBO> resolveHarmonicFields(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                                                   String phase, String statType, List<Integer> harmonicOrders) {
        List<Integer> orders = normalizeOrders(harmonicOrders);
        if (orders.isEmpty()) {
            throw fail("谐波次数不能为空");
        }
        if (orders.size() > MAX_HARMONIC_ORDER_COUNT) {
            throw fail("谐波次数不允许一次展示超过3个");
        }
        List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
        for (Integer order : orders) {
            if (order < indicator.getHarmonicOrderStart() || order > indicator.getHarmonicOrderEnd()) {
                throw fail("谐波次数只能在 " + indicator.getHarmonicOrderStart() + " 到 " + indicator.getHarmonicOrderEnd() + " 之间");
            }
            String field = indicator.getHarmonicFieldPrefix() + "_" + order;
            result.add(buildResolvedField(lineId, indicator, phase, statType, field, order + "次" + indicator.getName()));
        }
        return result;
    }

    private SteadyTrendResolvedFieldBO buildResolvedField(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                                          String phase, String statType, String field, String seriesName) {
        SteadyTrendResolvedFieldBO resolved = new SteadyTrendResolvedFieldBO();
        resolved.setMeasurement(indicator.getTableName());
        resolved.setField(field);
        resolved.setLineId(lineId);
        resolved.setIndicatorCode(indicator.getIndicatorCode());
        resolved.setIndicatorName(indicator.getName());
        resolved.setSeriesName(seriesName);
        resolved.setPhase(phase);
        resolved.setStatType(statType);
        resolved.setUnit(indicator.getUnit());
        resolved.setSeriesKey(lineId + "|" + indicator.getIndicatorCode() + "|" + phase + "|" + statType + "|" + field);
        return resolved;
    }

    private void validateBasicParam(SteadyTrendQueryParam param) {
        if (param == null) {
            throw fail("趋势查询参数不能为空");
        }
        List<String> lineIds = normalizeTextList(param.getLineIds());
        List<String> indicatorCodes = normalizeTextList(param.getIndicatorCodes());
        if (lineIds.isEmpty()) {
            throw fail("监测点 ID 不能为空");
        }
        if (indicatorCodes.isEmpty()) {
            throw fail("指标不能为空");
        }
        if (lineIds.size() > MAX_LINE_COUNT) {
            throw fail("监测点数量不能超过 8 个");
        }
        if (indicatorCodes.size() > MAX_INDICATOR_COUNT) {
            throw fail("指标数量不能超过 8 个");
        }
        if (lineIds.size() > 1 && indicatorCodes.size() > 1) {
            throw fail("多监测点查询时只能选择 1 个指标");
        }
        LocalDateTime startTime = parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        LocalDateTime endTime = parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
        if (startTime.isAfter(endTime)) {
            throw fail("开始时间不能大于结束时间");
        }
        if (param.getQualityFlag() != null && param.getQualityFlag() != 0 && param.getQualityFlag() != 1) {
            throw fail("质量标识只能是 0 或 1");
        }
    }

    private SteadyTrendIndicatorDefinitionBO requireIndicator(String indicatorCode) {
        SteadyTrendIndicatorDefinitionBO indicator = indicatorCatalog.getIndicator(indicatorCode);
        if (indicator == null) {
            throw fail("稳态趋势指标不支持：" + indicatorCode);
        }
        return indicator;
    }

    private List<String> resolvePhases(SteadyTrendIndicatorDefinitionBO indicator) {
        return new ArrayList<String>(indicator.getPhaseCodes());
    }

    private void validateStatType(SteadyTrendIndicatorDefinitionBO indicator, String statType) {
        if (!"AVG".equals(statType) && !"MAX".equals(statType) && !"MIN".equals(statType) && !"CP95".equals(statType)) {
            throw fail("统计类型只能是 AVG、MAX、MIN、CP95");
        }
        if (!indicator.getSupportStats().contains(statType)) {
            throw fail("指标 " + indicator.getIndicatorCode() + " 不支持统计类型：" + statType);
        }
    }

    private List<String> normalizeTextList(List<String> values) {
        if (values == null || values.isEmpty()) {
            return new ArrayList<String>();
        }
        List<String> result = new ArrayList<String>();
        for (String value : values) {
            String text = trimToNull(value);
            if (text != null && !result.contains(text)) {
                result.add(text);
            }
        }
        return result;
    }

    private List<String> normalizeUpperList(List<String> values) {
        List<String> result = normalizeTextList(values);
        for (int i = 0; i < result.size(); i++) {
            result.set(i, result.get(i).toUpperCase());
        }
        return result;
    }

    private List<Integer> normalizeOrders(List<Integer> orders) {
        if (orders == null || orders.isEmpty()) {
            return Collections.emptyList();
        }
        List<Integer> result = new ArrayList<Integer>();
        for (Integer order : orders) {
            if (order != null && !result.contains(order)) {
                result.add(order);
            }
        }
        return result;
    }

    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private BusinessException fail(String message) {
        return new BusinessException(CommonResponseEnum.FAIL, message);
    }
}
