import {
  PredictionResult,
  RAINBOW_COLORS,
  RISK_BREAKS,
  RISK_LABELS,
} from "./types";

export const HIGH_RISK_MAX_PROBABILITY = 0.3;
export const PRIORITY_PIPE_LIMIT = 20;

export interface RiskDistributionItem {
  label: string;
  color: string;
  count: number;
  ratio: number;
}

export interface HighRiskTrendPoint {
  year: number;
  count: number;
  validCount: number;
  ratio: number;
}

export interface PriorityPipeItem {
  linkId: string;
  probability: number;
  riskLabel: string;
  color: string;
}

export interface HealthRiskReportData {
  totalCount: number;
  validCount: number;
  invalidCount: number;
  averageProbability: number | null;
  highRiskCount: number;
  highRiskRatio: number;
  distribution: RiskDistributionItem[];
  trend: HighRiskTrendPoint[];
  priorityPipes: PriorityPipeItem[];
  conclusion: string;
  recommendations: string[];
}

const isValidProbability = (value: unknown): value is number =>
  typeof value === "number" &&
  Number.isFinite(value) &&
  value >= 0 &&
  value <= 1;

export const getProbabilityAtYear = (
  result: PredictionResult,
  year: number,
): number | null => {
  const yearIndex = result.survival_function.x.findIndex(
    (value) => value === year,
  );
  if (yearIndex < 0) return null;

  const probability = result.survival_function.y[yearIndex];
  return isValidProbability(probability) ? probability : null;
};

export const getRiskBandIndex = (probability: number): number => {
  const index = RISK_BREAKS.findIndex((upperBound) => probability <= upperBound);
  return index >= 0 ? index : RISK_BREAKS.length - 1;
};

export const buildHealthRiskReportData = (
  results: PredictionResult[],
  currentYear: number,
): HealthRiskReportData => {
  const currentValues = results.flatMap((result) => {
    const probability = getProbabilityAtYear(result, currentYear);
    return probability === null ? [] : [{ result, probability }];
  });
  const validCount = currentValues.length;
  const highRiskCount = currentValues.filter(
    ({ probability }) => probability <= HIGH_RISK_MAX_PROBABILITY,
  ).length;

  const distribution = RISK_LABELS.map((label, index) => {
    const count = currentValues.filter(
      ({ probability }) => getRiskBandIndex(probability) === index,
    ).length;
    return {
      label,
      color: RAINBOW_COLORS[index],
      count,
      ratio: validCount > 0 ? count / validCount : 0,
    };
  });

  const priorityPipes = currentValues
    .filter(
      ({ probability }) => probability <= HIGH_RISK_MAX_PROBABILITY,
    )
    .sort(
      (left, right) =>
        left.probability - right.probability ||
        left.result.link_id.localeCompare(right.result.link_id, "zh-CN", {
          numeric: true,
        }),
    )
    .slice(0, PRIORITY_PIPE_LIMIT)
    .map(({ result, probability }) => {
      const bandIndex = getRiskBandIndex(probability);
      return {
        linkId: result.link_id,
        probability,
        riskLabel: RISK_LABELS[bandIndex],
        color: RAINBOW_COLORS[bandIndex],
      };
    });

  const trendByYear = new Map<
    number,
    { count: number; validCount: number }
  >();
  results.forEach((result) => {
    const seenYears = new Set<number>();
    result.survival_function.x.forEach((year, index) => {
      if (
        typeof year !== "number" ||
        !Number.isFinite(year) ||
        seenYears.has(year)
      ) {
        return;
      }
      seenYears.add(year);
      const probability = result.survival_function.y[index];
      if (!isValidProbability(probability)) return;

      const point = trendByYear.get(year) ?? { count: 0, validCount: 0 };
      point.validCount += 1;
      if (probability <= HIGH_RISK_MAX_PROBABILITY) point.count += 1;
      trendByYear.set(year, point);
    });
  });
  const trend = Array.from(trendByYear, ([year, point]) => ({
    year,
    count: point.count,
    validCount: point.validCount,
    ratio: point.validCount > 0 ? point.count / point.validCount : 0,
  })).sort((left, right) => left.year - right.year);

  const averageProbability =
    validCount > 0
      ? currentValues.reduce(
          (total, { probability }) => total + probability,
          0,
        ) / validCount
      : null;
  const highRiskRatio = validCount > 0 ? highRiskCount / validCount : 0;
  const mediumRiskCount = currentValues.filter(
    ({ probability }) =>
      probability > HIGH_RISK_MAX_PROBABILITY && probability <= 0.6,
  ).length;

  const conclusion =
    validCount === 0
      ? `预测第 ${currentYear} 年没有可用于报告的有效生存概率数据。`
      : highRiskCount > 0
        ? `预测第 ${currentYear} 年发现 ${highRiskCount} 条较高及以上风险管段，占有效结果的 ${(highRiskRatio * 100).toFixed(1)}%。建议优先核查重点管段，并结合现场检测确认处置顺序。`
        : `预测第 ${currentYear} 年未发现较高及以上风险管段。当前结果仍需结合巡检记录持续跟踪。`;

  const recommendations: string[] = [];
  if (highRiskCount > 0) {
    recommendations.push(
      "优先核查重点风险管段的运行状态、历史故障和周边施工情况，必要时安排现场检测。",
    );
  }
  if (mediumRiskCount > 0) {
    recommendations.push(
      `对其余 ${mediumRiskCount} 条中等风险管段提高监测频率，关注压力波动和风险趋势变化。`,
    );
  }
  if (highRiskCount === 0 && mediumRiskCount === 0 && validCount > 0) {
    recommendations.push(
      "保持现有巡检和监测频率，在新的在线模拟数据产生后重新评估。",
    );
  }
  recommendations.push(
    "本报告为模型预测结果，仅用于辅助决策，不能替代现场检测、专业鉴定和安全处置流程。",
  );

  return {
    totalCount: results.length,
    validCount,
    invalidCount: results.length - validCount,
    averageProbability,
    highRiskCount,
    highRiskRatio,
    distribution,
    trend,
    priorityPipes,
    conclusion,
    recommendations,
  };
};
