import "server-only"

import { createId } from "@paralleldrive/cuid2"
import { and, desc, eq, type SQL } from "drizzle-orm"
import { cache } from "react"

import { db } from "@/shared/db"
import { learningDiagnosticReports } from "@/shared/db/schema"
import { getUserNamesByIds } from "@/modules/users/data-access"

import { getClassMasterySummary, getStudentMasterySummary } from "./data-access"
import type {
  DiagnosticReport,
  DiagnosticReportQueryParams,
  DiagnosticReportWithDetails,
} from "./types"

const toNumber = (v: unknown): number => {
  const n = typeof v === "number" ? v : Number(v)
  return Number.isFinite(n) ? n : 0
}

const isStringArray = (v: unknown): v is string[] =>
  Array.isArray(v) && v.every((item) => typeof item === "string")

const toStringArrayNullable = (v: unknown): string[] | null =>
  isStringArray(v) ? v : null

const serializeReport = (r: typeof learningDiagnosticReports.$inferSelect): DiagnosticReport => ({
  id: r.id,
  studentId: r.studentId,
  generatedBy: r.generatedBy,
  reportType: r.reportType,
  period: r.period,
  summary: r.summary,
  strengths: toStringArrayNullable(r.strengths),
  weaknesses: toStringArrayNullable(r.weaknesses),
  recommendations: toStringArrayNullable(r.recommendations),
  overallScore: r.overallScore !== null ? toNumber(r.overallScore) : null,
  status: r.status,
  createdAt: r.createdAt.toISOString(),
  updatedAt: r.updatedAt.toISOString(),
})

/** 生成个人诊断报告 */
export async function generateDiagnosticReport(
  studentId: string,
  period: string,
  generatedBy: string
): Promise<string> {
  const summary = await getStudentMasterySummary(studentId)
  if (!summary) throw new Error("Student not found")

  const overallScore = summary.averageMastery
  const strengths = summary.strengths.map((m) => `${m.knowledgePointName} (${m.masteryLevel.toFixed(1)}%)`)
  const weaknesses = summary.weaknesses.map((m) => `${m.knowledgePointName} (${m.masteryLevel.toFixed(1)}%)`)
  const recommendations = summary.weaknesses.map(
    (m) => `建议复习「${m.knowledgePointName}」知识点，多做相关练习以提升掌握度（当前 ${m.masteryLevel.toFixed(1)}%）。`
  )
  if (recommendations.length === 0) {
    recommendations.push("整体掌握情况良好，建议保持当前学习节奏并挑战更高难度题目。")
  }

  const summaryText = `学生 ${summary.studentName} 在 ${period} 期间整体掌握度 ${overallScore.toFixed(1)}%，共评估 ${summary.totalKnowledgePoints} 个知识点，强项 ${strengths.length} 个，弱项 ${weaknesses.length} 个。`

  const id = createId()
  await db.insert(learningDiagnosticReports).values({
    id,
    studentId,
    generatedBy,
    reportType: "individual",
    period,
    summary: summaryText,
    strengths,
    weaknesses,
    recommendations,
    overallScore: String(overallScore),
    status: "draft",
  })
  return id
}

/** 生成班级诊断报告 */
export async function generateClassDiagnosticReport(
  classId: string,
  period: string,
  generatedBy: string
): Promise<string> {
  const summary = await getClassMasterySummary(classId)
  if (!summary) throw new Error("Class not found")

  const topWeak = summary.knowledgePointStats
    .filter((k) => k.averageMastery < 60)
    .sort((a, b) => a.averageMastery - b.averageMastery)
    .slice(0, 5)
  const strengths = summary.knowledgePointStats
    .filter((k) => k.averageMastery >= 80)
    .map((k) => `${k.knowledgePointName} (均 ${k.averageMastery.toFixed(1)}%)`)
  const weaknesses = topWeak.map((k) => `${k.knowledgePointName} (均 ${k.averageMastery.toFixed(1)}%)`)
  const recommendations = topWeak.map(
    (k) => `班级在「${k.knowledgePointName}」整体掌握度偏低（${k.averageMastery.toFixed(1)}%），建议安排专项复习与巩固练习。`
  )
  if (recommendations.length === 0) {
    recommendations.push("班级整体掌握情况良好，建议保持当前教学节奏。")
  }

  const summaryText = `班级 ${summary.className} 在 ${period} 期间整体掌握度 ${summary.averageMastery.toFixed(1)}%，学生 ${summary.studentCount} 人，需重点关注 ${summary.studentsNeedingAttention.length} 人。`

  const id = createId()
  await db.insert(learningDiagnosticReports).values({
    id,
    studentId: null, // 班级报告无单个学生，studentId 置空（P2-3 修复：不再存生成者 ID）
    generatedBy,
    reportType: "class",
    period,
    summary: summaryText,
    strengths,
    weaknesses,
    recommendations,
    overallScore: String(summary.averageMastery),
    status: "draft",
  })
  return id
}

/** 查询诊断报告列表 */
export const getDiagnosticReports = cache(
  async (filters: DiagnosticReportQueryParams): Promise<DiagnosticReportWithDetails[]> => {
    const conditions: SQL[] = []
    if (filters.studentId) conditions.push(eq(learningDiagnosticReports.studentId, filters.studentId))
    if (filters.reportType) conditions.push(eq(learningDiagnosticReports.reportType, filters.reportType))
    if (filters.status) conditions.push(eq(learningDiagnosticReports.status, filters.status))
    if (filters.period) conditions.push(eq(learningDiagnosticReports.period, filters.period))

    const rows = await db
      .select({ report: learningDiagnosticReports })
      .from(learningDiagnosticReports)
      .where(conditions.length > 0 ? and(...conditions) : undefined)
      .orderBy(desc(learningDiagnosticReports.createdAt))

    // 收集所有需要查询姓名的用户 ID（学生 + 生成者），通过 users data-access 统一获取
    const userIds = new Set<string>()
    for (const r of rows) {
      if (r.report.studentId) userIds.add(r.report.studentId)
      if (r.report.generatedBy) userIds.add(r.report.generatedBy)
    }
    const userMap = await getUserNamesByIds(Array.from(userIds))

    return rows.map((r) => ({
      ...serializeReport(r.report),
      studentName: r.report.studentId
        ? userMap.get(r.report.studentId)?.name ?? "Unknown"
        : null,
      generatedByName: r.report.generatedBy
        ? userMap.get(r.report.generatedBy)?.name ?? "Unknown"
        : null,
    }))
  },
)

/** 获取报告详情 */
export const getDiagnosticReportById = cache(
  async (id: string): Promise<DiagnosticReportWithDetails | null> => {
    const [row] = await db
      .select({ report: learningDiagnosticReports })
      .from(learningDiagnosticReports)
      .where(eq(learningDiagnosticReports.id, id))
      .limit(1)
    if (!row) return null

    // 通过 users data-access 获取学生姓名和生成者姓名
    const userIds: string[] = []
    if (row.report.studentId) userIds.push(row.report.studentId)
    if (row.report.generatedBy) userIds.push(row.report.generatedBy)
    const userMap = await getUserNamesByIds(userIds)

    return {
      ...serializeReport(row.report),
      studentName: row.report.studentId
        ? userMap.get(row.report.studentId)?.name ?? "Unknown"
        : null,
      generatedByName: row.report.generatedBy
        ? userMap.get(row.report.generatedBy)?.name ?? null
        : null,
    }
  },
)

/** 发布诊断报告 */
export async function publishDiagnosticReport(id: string): Promise<void> {
  await db
    .update(learningDiagnosticReports)
    .set({ status: "published", updatedAt: new Date() })
    .where(eq(learningDiagnosticReports.id, id))
}

/** 删除诊断报告 */
export async function deleteDiagnosticReport(id: string): Promise<void> {
  await db.delete(learningDiagnosticReports).where(eq(learningDiagnosticReports.id, id))
}
