/**
 * V5-20 T4：课标覆盖度统计（教师端课标热力图支撑）。
 *
 * 统计教师所有课案对教材知识点的覆盖情况：
 * - 每个知识点被多少个课案覆盖
 * - 未被覆盖的知识点（教学盲点）
 * - 按章节分组的覆盖率
 *
 * 纯函数，输入数据由调用方从 data-access 获取。
 */
import type { KnowledgePoint } from "@/modules/textbooks/types";

/** 单个知识点的覆盖统计 */
export interface KpCoverageStat {
  kpId: string;
  kpName: string;
  chapterId: string | null;
  /** 覆盖此知识点的课案数量 */
  planCount: number;
  /** 覆盖此知识点的课案 ID 列表 */
  planIds: string[];
  /** 是否为教学盲点（planCount === 0） */
  isBlindSpot: boolean;
}

/** 章节覆盖率统计 */
export interface ChapterCoverageStat {
  chapterId: string;
  /** 该章节下知识点总数 */
  totalKps: number;
  /** 被覆盖的知识点数 */
  coveredKps: number;
  /** 覆盖率（0-100） */
  coverageRate: number;
  /** 章节下的知识点统计 */
  kps: KpCoverageStat[];
}

/** 课标热力图统计结果 */
export interface CurriculumCoverageResult {
  /** 按章节分组 */
  chapters: ChapterCoverageStat[];
  /** 总知识点数 */
  totalKps: number;
  /** 被覆盖的知识点数 */
  coveredKps: number;
  /** 整体覆盖率（0-100） */
  overallCoverageRate: number;
  /** 教学盲点（未被任何课案覆盖的知识点） */
  blindSpots: KpCoverageStat[];
}

/** 课案知识点关联的扁平结构（由调用方从 LessonPlanDocument 提取） */
export interface PlanKpLink {
  planId: string;
  knowledgePointIds: string[];
}

/**
 * 计算课标覆盖度热力图数据。纯函数，无副作用。
 *
 * @param allKps 教材下所有知识点（由 getKnowledgePointsByTextbookId 获取）
 * @param planLinks 教师所有课案的知识点关联列表
 */
export function computeCurriculumCoverage(
  allKps: KnowledgePoint[],
  planLinks: PlanKpLink[],
): CurriculumCoverageResult {
  // 构建知识点 → 课案列表 的反向索引
  const kpToPlans = new Map<string, { planIds: string[]; count: number }>();
  for (const link of planLinks) {
    for (const kpId of link.knowledgePointIds) {
      const existing = kpToPlans.get(kpId);
      if (existing) {
        if (!existing.planIds.includes(link.planId)) {
          existing.planIds.push(link.planId);
          existing.count++;
        }
      } else {
        kpToPlans.set(kpId, { planIds: [link.planId], count: 1 });
      }
    }
  }

  // 按章节分组知识点
  const chapterMap = new Map<string, KnowledgePoint[]>();
  for (const kp of allKps) {
    const chId = kp.chapterId ?? "__no_chapter__";
    if (!chapterMap.has(chId)) chapterMap.set(chId, []);
    chapterMap.get(chId)!.push(kp);
  }

  const chapters: ChapterCoverageStat[] = [];
  let totalKps = 0;
  let coveredKps = 0;
  const blindSpots: KpCoverageStat[] = [];

  for (const [chapterId, kps] of chapterMap) {
    const kpStats: KpCoverageStat[] = kps.map((kp) => {
      const coverage = kpToPlans.get(kp.id);
      const planIds = coverage?.planIds ?? [];
      const planCount = coverage?.count ?? 0;
      const stat: KpCoverageStat = {
        kpId: kp.id,
        kpName: kp.name,
        chapterId: kp.chapterId ?? null,
        planCount,
        planIds,
        isBlindSpot: planCount === 0,
      };
      if (stat.isBlindSpot) blindSpots.push(stat);
      return stat;
    });

    const chapterTotal = kps.length;
    const chapterCovered = kpStats.filter((s) => !s.isBlindSpot).length;
    const coverageRate = chapterTotal === 0 ? 0 : Math.round((chapterCovered / chapterTotal) * 100);

    chapters.push({
      chapterId,
      totalKps: chapterTotal,
      coveredKps: chapterCovered,
      coverageRate,
      kps: kpStats,
    });

    totalKps += chapterTotal;
    coveredKps += chapterCovered;
  }

  const overallCoverageRate = totalKps === 0 ? 0 : Math.round((coveredKps / totalKps) * 100);

  return {
    chapters,
    totalKps,
    coveredKps,
    overallCoverageRate,
    blindSpots,
  };
}

/** 根据覆盖率返回热力图颜色等级（0-4） */
export function getHeatLevel(coverageRate: number): 0 | 1 | 2 | 3 | 4 {
  if (coverageRate === 0) return 0;
  if (coverageRate < 25) return 1;
  if (coverageRate < 50) return 2;
  if (coverageRate < 75) return 3;
  return 4;
}
