/**
 * 成绩计算器（纯函数）
 *
 * 支持的公式类型：
 *   - weighted_average: 加权平均（weights JSON: { examId/homeworkId: weight }）
 *   - sum: 直接求和
 *   - custom: 自定义表达式（P3 仅预留，不执行）
 *
 * Scope 优先级（ISSUE-006 决策 #3）：class > subject > school
 */
export type GradeScope = "class" | "subject" | "school";

export type FormulaType = "weighted_average" | "sum" | "custom";

export interface GradeFormulaConfig {
  scope: GradeScope;
  scopeId: string;
  formulaType: FormulaType;
  weights: Record<string, number> | null;
  customExpression: string | null;
  effectiveFrom: Date;
  effectiveTo: Date | null;
}

export interface ScoreEntry {
  sourceId: string; // examId or homeworkId
  score: number;
  totalScore: number;
}

const SCOPE_PRIORITY: Record<GradeScope, number> = {
  class: 3,
  subject: 2,
  school: 1,
};

/**
 * 按 scope 优先级选择生效公式（class > subject > school）。
 * 同时满足 effectiveFrom <= now < effectiveTo（如果 effectiveTo 存在）。
 */
export function selectFormula(
  formulas: GradeFormulaConfig[],
  now: Date = new Date(),
): GradeFormulaConfig | null {
  const effective = formulas.filter((f) => {
    if (f.effectiveFrom > now) return false;
    if (f.effectiveTo && f.effectiveTo <= now) return false;
    return true;
  });

  if (effective.length === 0) return null;

  effective.sort((a, b) => SCOPE_PRIORITY[b.scope] - SCOPE_PRIORITY[a.scope]);
  return effective[0]!;
}

/**
 * 计算最终成绩。
 * - weighted_average: Σ(score * weight) / Σ(weight)
 * - sum: Σ(score)
 * - custom: P3 不执行，抛出错误
 */
export function calculateGrade(
  formula: GradeFormulaConfig,
  entries: ScoreEntry[],
): number {
  switch (formula.formulaType) {
    case "weighted_average": {
      if (!formula.weights) {
        // 无权重时退化为简单平均
        if (entries.length === 0) return 0;
        const sum = entries.reduce((acc, e) => acc + e.score, 0);
        return Math.round((sum / entries.length) * 100) / 100;
      }
      let weightedSum = 0;
      let totalWeight = 0;
      for (const entry of entries) {
        const weight = formula.weights[entry.sourceId] ?? 0;
        weightedSum += entry.score * weight;
        totalWeight += weight;
      }
      if (totalWeight === 0) return 0;
      return Math.round((weightedSum / totalWeight) * 100) / 100;
    }
    case "sum": {
      return (
        Math.round(entries.reduce((acc, e) => acc + e.score, 0) * 100) / 100
      );
    }
    case "custom": {
      throw new Error(
        "Custom grade formula is not supported in P3 (reserved for future)",
      );
    }
  }
}
