/**
 * M10 备课分析仪表盘 - 数据访问层
 *
 * 查询备课分析快照表 + 课标覆盖热力图 + 模板使用率统计。
 * 用于 admin 备课分析仪表盘的 3 张图表：
 * - 教师备课投入（按日聚合）
 * - 模板使用率（按 template 分组）
 * - 课标覆盖热力图（按 subject+grade 矩阵）
 */
import "server-only";
import { db } from "@/shared/db";
import {
  lessonPlanAnalyticsDaily,
  lessonPlans,
  lessonPlanStandards,
} from "@/shared/db/schema";
import { and, eq, gte, lte, desc, sql, count } from "drizzle-orm";
import type { LessonPlanStatus } from "./types";

/** 教师备课投入数据点 */
export interface TeacherInvestmentDataPoint {
  snapshotDate: Date;
  teacherId: string;
  newPlansCount: number;
  editDurationMin: number;
  savedVersionsCount: number;
  submittedCount: number;
  publishedCount: number;
  standardsLinked: number;
}

/** 模板使用率数据点 */
export interface TemplateUsageDataPoint {
  templateId: string;
  templateName: string;
  usageCount: number;
}

/** 课标覆盖热力图单元 */
export interface StandardsCoverageCell {
  subjectId: string | null;
  gradeId: string | null;
  totalPlans: number;
  standardsLinkedPlans: number;
  coveragePercent: number;
}

/**
 * 查询教师备课投入（按日期范围）
 */
export async function getTeacherInvestment(
  startDate: Date,
  endDate: Date,
  teacherId?: string,
): Promise<TeacherInvestmentDataPoint[]> {
  const conditions = [
    gte(lessonPlanAnalyticsDaily.snapshotDate, startDate),
    lte(lessonPlanAnalyticsDaily.snapshotDate, endDate),
  ];
  if (teacherId) conditions.push(eq(lessonPlanAnalyticsDaily.teacherId, teacherId));

  const rows = await db
    .select()
    .from(lessonPlanAnalyticsDaily)
    .where(and(...conditions))
    .orderBy(desc(lessonPlanAnalyticsDaily.snapshotDate));

  return rows.map((r) => ({
    snapshotDate: r.snapshotDate,
    teacherId: r.teacherId,
    newPlansCount: r.newPlansCount,
    editDurationMin: r.editDurationMin,
    savedVersionsCount: r.savedVersionsCount,
    submittedCount: r.submittedCount,
    publishedCount: r.publishedCount,
    standardsLinked: r.standardsLinked,
  }));
}

/**
 * 查询模板使用率（按 templateId 分组）
 */
export async function getTemplateUsageStats(): Promise<TemplateUsageDataPoint[]> {
  const rows = await db
    .select({
      templateId: lessonPlans.templateId,
      templateName: lessonPlans.templateName,
      usageCount: count(lessonPlans.id),
    })
    .from(lessonPlans)
    .where(sql`${lessonPlans.templateId} IS NOT NULL`)
    .groupBy(lessonPlans.templateId, lessonPlans.templateName)
    .orderBy(desc(count(lessonPlans.id)));

  return rows.map((r) => ({
    templateId: r.templateId!,
    templateName: r.templateName ?? "(unknown)",
    usageCount: r.usageCount,
  }));
}

/**
 * 查询课标覆盖热力图（按 subject+grade 矩阵）
 */
export async function getStandardsCoverageHeatmap(): Promise<
  StandardsCoverageCell[]
> {
  // 总课案数（按 subject+grade 分组）
  const totalRows = await db
    .select({
      subjectId: lessonPlans.subjectId,
      gradeId: lessonPlans.gradeId,
      total: count(lessonPlans.id),
    })
    .from(lessonPlans)
    .where(sql`${lessonPlans.subjectId} IS NOT NULL AND ${lessonPlans.gradeId} IS NOT NULL`)
    .groupBy(lessonPlans.subjectId, lessonPlans.gradeId);

  // 关联课标的课案数（按 subject+grade 分组）
  const linkedRows = await db
    .select({
      subjectId: lessonPlans.subjectId,
      gradeId: lessonPlans.gradeId,
      linkedCount: sql<number>`COUNT(DISTINCT ${lessonPlanStandards.planId})`,
    })
    .from(lessonPlanStandards)
    .innerJoin(lessonPlans, eq(lessonPlanStandards.planId, lessonPlans.id))
    .where(sql`${lessonPlans.subjectId} IS NOT NULL AND ${lessonPlans.gradeId} IS NOT NULL`)
    .groupBy(lessonPlans.subjectId, lessonPlans.gradeId);

  const linkedMap = new Map<string, number>();
  for (const r of linkedRows) {
    const key = `${r.subjectId ?? ""}|${r.gradeId ?? ""}`;
    linkedMap.set(key, Number(r.linkedCount));
  }

  return totalRows.map((r) => {
    const key = `${r.subjectId ?? ""}|${r.gradeId ?? ""}`;
    const linkedCount = linkedMap.get(key) ?? 0;
    const total = Number(r.total);
    return {
      subjectId: r.subjectId,
      gradeId: r.gradeId,
      totalPlans: total,
      standardsLinkedPlans: linkedCount,
      coveragePercent: total > 0 ? Math.round((linkedCount / total) * 100) : 0,
    };
  });
}

/**
 * 查询全局备课统计（仪表盘顶部卡片）
 */
export async function getGlobalLessonPlanStats(): Promise<{
  totalTeachers: number;
  totalPlans: number;
  totalPublished: number;
  totalSubmitted: number;
  totalStandardsLinked: number;
  averageScore: number | null;
}> {
  const totalTeachersRows = await db
    .select({ count: sql<number>`COUNT(DISTINCT ${lessonPlans.creatorId})` })
    .from(lessonPlans);
  const totalPlansRows = await db
    .select({ count: count() })
    .from(lessonPlans);
  const publishedRows = await db
    .select({ count: count() })
    .from(lessonPlans)
    .where(eq(lessonPlans.status, "published" as LessonPlanStatus));
  const submittedRows = await db
    .select({ count: count() })
    .from(lessonPlans)
    .where(eq(lessonPlans.status, "submitted" as LessonPlanStatus));
  const standardsRows = await db
    .select({ count: count() })
    .from(lessonPlanStandards);

  return {
    totalTeachers: Number(totalTeachersRows[0]?.count ?? 0),
    totalPlans: Number(totalPlansRows[0]?.count ?? 0),
    totalPublished: Number(publishedRows[0]?.count ?? 0),
    totalSubmitted: Number(submittedRows[0]?.count ?? 0),
    totalStandardsLinked: Number(standardsRows[0]?.count ?? 0),
    averageScore: null, // TODO: 聚合 lessonPlanAiEvaluations
  };
}

/**
 * 写入或更新当日分析快照（教师保存版本时触发）
 */
export async function upsertDailyAnalytics(
  snapshotDate: Date,
  teacherId: string,
  subjectId: string | null,
  gradeId: string | null,
  patch: Partial<TeacherInvestmentDataPoint>,
): Promise<void> {
  // 简化实现：先尝试更新，不存在则插入
  const existing = await db
    .select()
    .from(lessonPlanAnalyticsDaily)
    .where(
      and(
        eq(lessonPlanAnalyticsDaily.snapshotDate, snapshotDate),
        eq(lessonPlanAnalyticsDaily.teacherId, teacherId),
      ),
    )
    .limit(1);

  if (existing.length > 0) {
    const row = existing[0]!;
    await db
      .update(lessonPlanAnalyticsDaily)
      .set({
        newPlansCount: (row.newPlansCount ?? 0) + (patch.newPlansCount ?? 0),
        editDurationMin:
          (row.editDurationMin ?? 0) + (patch.editDurationMin ?? 0),
        savedVersionsCount:
          (row.savedVersionsCount ?? 0) + (patch.savedVersionsCount ?? 0),
        submittedCount: (row.submittedCount ?? 0) + (patch.submittedCount ?? 0),
        publishedCount: (row.publishedCount ?? 0) + (patch.publishedCount ?? 0),
        standardsLinked: (row.standardsLinked ?? 0) + (patch.standardsLinked ?? 0),
      })
      .where(eq(lessonPlanAnalyticsDaily.id, row.id));
  } else {
    await db.insert(lessonPlanAnalyticsDaily).values({
      snapshotDate,
      teacherId,
      subjectId,
      gradeId,
      newPlansCount: patch.newPlansCount ?? 0,
      editDurationMin: patch.editDurationMin ?? 0,
      savedVersionsCount: patch.savedVersionsCount ?? 0,
      submittedCount: patch.submittedCount ?? 0,
      publishedCount: patch.publishedCount ?? 0,
      standardsLinked: patch.standardsLinked ?? 0,
    });
  }
}
