import "server-only"

import { env } from "@/env.mjs"
import { createAiChatCompletion, getAiErrorMessage } from "@/shared/lib/ai"

import {
  GRADING_ASSIST_SYSTEM_PROMPT,
  LESSON_CONTENT_SYSTEM_PROMPT,
  QUESTION_VARIANT_SYSTEM_PROMPT,
  SIMILAR_QUESTION_SYSTEM_PROMPT,
  WEAKNESS_ANALYSIS_SYSTEM_PROMPT,
  CHILD_SUMMARY_SYSTEM_PROMPT,
  STUDY_PATH_SYSTEM_PROMPT,
  EXPLAIN_ERROR_SYSTEM_PROMPT,
} from "./prompt-templates"
import { withAiTracking } from "./usage-tracker"
import {
  GradingSuggestionSchema,
  LessonContentResultSchema,
  QuestionVariantResultSchema,
  SimilarQuestionListSchema,
  WeaknessAnalysisResultSchema,
  ChildSummaryResultSchema,
  StudyPathResultSchema,
  ExplainErrorResultSchema,
} from "../schema"
import type {
  AiChatMessage,
  AiChatOptions,
  AiChatResult,
  AiService,
  GradingInput,
  GradingSuggestion,
  LessonContentInput,
  LessonContentResult,
  QuestionVariantInput,
  QuestionVariantResult,
  SimilarQuestionInput,
  SimilarQuestionResult,
  WeaknessAnalysisInput,
  WeaknessAnalysisResult,
  ChildSummaryInput,
  ChildSummaryResult,
  StudyPathInput,
  StudyPathResult,
  ExplainErrorInput,
  ExplainErrorResult,
} from "../types"

// ---------------------------------------------------------------------------
// JSON 提取工具（从 AI 返回文本中提取 JSON）
// ---------------------------------------------------------------------------

const extractBalancedJsonSegment = (value: string): string | null => {
  const startBrace = value.indexOf("{")
  const startBracket = value.indexOf("[")
  const start =
    startBrace === -1
      ? startBracket
      : startBracket === -1
        ? startBrace
        : Math.min(startBrace, startBracket)
  if (start === -1) return null
  const opening = value[start]
  const closing = opening === "{" ? "}" : "]"
  let depth = 0
  let inString = false
  let escaped = false
  for (let i = start; i < value.length; i += 1) {
    const char = value[i]
    if (inString) {
      if (escaped) {
        escaped = false
      } else if (char === "\\") {
        escaped = true
      } else if (char === '"') {
        inString = false
      }
      continue
    }
    if (char === '"') {
      inString = true
      continue
    }
    if (char === opening) {
      depth += 1
      continue
    }
    if (char === closing) {
      depth -= 1
      if (depth === 0) {
        return value.slice(start, i + 1)
      }
    }
  }
  return null
}

const tryParseJson = (value: string): unknown | null => {
  try {
    return JSON.parse(value)
  } catch {
    return null
  }
}

const extractJson = (raw: string): unknown => {
  const trimmed = raw.trim()
  const candidates: string[] = []
  const fencedMatches = [...trimmed.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi)]
  if (fencedMatches.length > 0) {
    candidates.push(...fencedMatches.map((match) => (match[1] ?? "").trim()))
  }
  candidates.push(trimmed)
  for (const candidate of candidates) {
    const direct = tryParseJson(candidate)
    if (direct !== null) return direct
    const segment = extractBalancedJsonSegment(candidate)
    if (!segment) continue
    const parsed = tryParseJson(segment)
    if (parsed !== null) return parsed
  }
  throw new Error("Invalid AI response: cannot parse JSON")
}

// ---------------------------------------------------------------------------
// AiService 实现
// ---------------------------------------------------------------------------

const DEFAULT_MODEL = () => String(env.AI_MODEL ?? "gpt-4o-mini")

const buildChatMessages = (
  systemPrompt: string,
  userContent: string
): AiChatMessage[] => [
  { role: "system", content: systemPrompt },
  { role: "user", content: userContent },
]

const callAi = async (
  messages: AiChatMessage[],
  options?: AiChatOptions
): Promise<{ content: string; model?: string; tokenUsage?: number }> => {
  const result = await createAiChatCompletion({
    messages,
    model: options?.model ?? DEFAULT_MODEL(),
    temperature: options?.temperature ?? 0.3,
    ...(typeof options?.maxTokens === "number" ? { maxTokens: options.maxTokens } : {}),
    ...(options?.providerId ? { providerId: options.providerId } : {}),
  })
  // 从 unknown 类型安全提取 total_tokens（避免 as 断言）
  const tokenUsage =
    result.usage && typeof result.usage === "object" && "total_tokens" in result.usage
      ? Number(result.usage.total_tokens ?? 0)
      : undefined
  return { content: result.content, tokenUsage }
}

/**
 * 默认 AI 服务实现
 *
 * 封装 shared/lib/ai 的底层 SDK 调用，提供业务语义化接口。
 * 所有业务模块通过此服务调用 AI，不直接 import shared/lib/ai。
 */
export class DefaultAiService implements AiService {
  constructor(private readonly userId: string) {}

  async chat(
    messages: AiChatMessage[],
    options?: AiChatOptions
  ): Promise<AiChatResult> {
    return withAiTracking(this.userId, "chat", options?.providerId, async () => {
      const { content, tokenUsage } = await callAi(messages, {
        ...options,
        temperature: options?.temperature ?? 0.7,
      })
      // usage 字段返回 token 用量对象（unknown 类型），便于调用方按需类型缩小
      return {
        result: { content, usage: tokenUsage !== undefined ? { total_tokens: tokenUsage } : null },
        tokenUsage,
      }
    })
  }

  async suggestSimilarQuestions(
    input: SimilarQuestionInput
  ): Promise<SimilarQuestionResult[]> {
    return withAiTracking(this.userId, "similar_question", undefined, async () => {
      const count = input.count ?? 3
      const userLines = [
        `Question Type: ${input.questionType}`,
        input.subject ? `Subject: ${input.subject}` : "",
        input.knowledgePointIds?.length
          ? `Knowledge Points: ${input.knowledgePointIds.join(", ")}`
          : "",
        `Generate ${count} similar questions.`,
        `Original Question:\n${input.questionText}`,
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(SIMILAR_QUESTION_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.5, maxTokens: 3000 }
      )
      const parsed = extractJson(content)
      // 安全提取 questions 字段（使用 in 操作符类型缩小，无需 as 断言）
      const list =
        parsed && typeof parsed === "object" && "questions" in parsed
          ? parsed.questions
          : parsed
      const validated = SimilarQuestionListSchema.safeParse(list)
      if (!validated.success) return { result: [] }
      return { result: validated.data }
    })
  }

  async suggestGrading(input: GradingInput): Promise<GradingSuggestion> {
    return withAiTracking(this.userId, "grading_assist", undefined, async () => {
      const userLines = [
        `Question Type: ${input.questionType}`,
        `Max Score: ${input.maxScore}`,
        input.subject ? `Subject: ${input.subject}` : "",
        `Question:\n${input.questionText}`,
        `Student Answer:\n${input.studentAnswer}`,
        input.correctAnswer ? `Correct Answer:\n${input.correctAnswer}` : "",
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(GRADING_ASSIST_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.2, maxTokens: 1000 }
      )
      const parsed = extractJson(content)
      const validated = GradingSuggestionSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            suggestedScore: 0,
            confidence: 0,
            feedback: "AI grading unavailable",
            reasoning: "AI response format invalid",
          },
        }
      }
      const data = validated.data
      return {
        result: {
          suggestedScore: Math.min(Math.max(data.suggestedScore, 0), input.maxScore),
          confidence: data.confidence,
          feedback: data.feedback,
          reasoning: data.reasoning,
        },
      }
    })
  }

  async generateLessonContent(
    input: LessonContentInput
  ): Promise<LessonContentResult> {
    return withAiTracking(this.userId, "lesson_content", undefined, async () => {
      const userLines = [
        `Topic: ${input.topic}`,
        `Content Type: ${input.contentType}`,
        input.subject ? `Subject: ${input.subject}` : "",
        input.grade ? `Grade: ${input.grade}` : "",
        input.additionalContext ? `Additional Context:\n${input.additionalContext}` : "",
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(LESSON_CONTENT_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.7, maxTokens: 4000 }
      )
      const parsed = extractJson(content)
      const validated = LessonContentResultSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            title: input.topic,
            content: content,
          },
        }
      }
      return { result: validated.data }
    })
  }

  async generateQuestionVariant(
    input: QuestionVariantInput
  ): Promise<QuestionVariantResult> {
    return withAiTracking(this.userId, "question_variant", undefined, async () => {
      const userLines = [
        `Variant Type: ${input.variantType}`,
        input.subject ? `Subject: ${input.subject}` : "",
        `Original Question:\n${JSON.stringify(input.originalQuestion, null, 2)}`,
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(QUESTION_VARIANT_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.6, maxTokens: 2000 }
      )
      const parsed = extractJson(content)
      const validated = QuestionVariantResultSchema.safeParse(parsed)
      if (!validated.success) {
        throw new Error("AI question variant format invalid")
      }
      return { result: validated.data }
    })
  }

  async analyzeWeakness(
    input: WeaknessAnalysisInput
  ): Promise<WeaknessAnalysisResult> {
    return withAiTracking(this.userId, "weakness_analysis", undefined, async () => {
      const userLines = [
        `Student ID: ${input.studentId}`,
        input.subjectId ? `Subject ID: ${input.subjectId}` : "",
        `Error Items (${input.errorItems.length}):`,
        JSON.stringify(
          input.errorItems.map((item) => ({
            questionText: item.questionText,
            questionType: item.questionType,
            errorCount: item.errorCount,
            masteryLevel: item.masteryLevel,
          })),
          null,
          2
        ),
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(WEAKNESS_ANALYSIS_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.3, maxTokens: 2000 }
      )
      const parsed = extractJson(content)
      const validated = WeaknessAnalysisResultSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            weakAreas: [],
            studyPlan: "Analysis unavailable",
            recommendedResources: [],
          },
        }
      }
      return { result: validated.data }
    })
  }

  async generateChildSummary(input: ChildSummaryInput): Promise<ChildSummaryResult> {
    return withAiTracking(this.userId, "child_summary", undefined, async () => {
      // PII 最小化：不传学生真实姓名，用 ID 替代（COPPA/FERPA 合规）
      const userLines = [
        `Student ID: ${input.studentId}`,
        input.grade ? `Grade: ${input.grade}` : "",
        input.recentGrades && input.recentGrades.length > 0
          ? `Recent Grades:\n${JSON.stringify(input.recentGrades, null, 2)}`
          : "",
        input.attendanceRate !== undefined
          ? `Attendance Rate: ${(input.attendanceRate * 100).toFixed(1)}%`
          : "",
        input.errorBookSummary
          ? `Error Book Summary:\n${JSON.stringify(input.errorBookSummary, null, 2)}`
          : "",
        input.homeworkCompletionRate !== undefined
          ? `Homework Completion Rate: ${(input.homeworkCompletionRate * 100).toFixed(1)}%`
          : "",
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(CHILD_SUMMARY_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.4, maxTokens: 2000 }
      )
      const parsed = extractJson(content)
      const validated = ChildSummaryResultSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            overallAssessment: "Unable to generate summary at this time.",
            strengths: [],
            areasForImprovement: [],
            familyTutoringSuggestions: [],
            nextSteps: [],
          },
        }
      }
      return { result: validated.data }
    })
  }

  async recommendStudyPath(input: StudyPathInput): Promise<StudyPathResult> {
    return withAiTracking(this.userId, "study_path", undefined, async () => {
      const userLines = [
        `Student ID: ${input.studentId}`,
        input.subject ? `Subject: ${input.subject}` : "",
        input.currentMastery && input.currentMastery.length > 0
          ? `Current Mastery:\n${JSON.stringify(input.currentMastery, null, 2)}`
          : "",
        input.learningGoal ? `Learning Goal: ${input.learningGoal}` : "",
      ].filter((line) => line.length > 0)

      // 知识图谱上下文注入（V3：对标 Squirrel AI 纳米级知识图谱）
      if (input.knowledgeGraph && input.knowledgeGraph.nodes.length > 0) {
        const graphLines = [
          "Knowledge Graph:",
          "Nodes (id | name | level | mastery 0-100):",
          ...input.knowledgeGraph.nodes.map(
            (n) => `  ${n.id} | ${n.name} | L${n.level} | ${n.masteryLevel ?? "unassessed"}`
          ),
          "Prerequisite edges (from -> to, meaning 'from' must be mastered before 'to'):",
          ...input.knowledgeGraph.edges.map((e) => `  ${e.from} -> ${e.to}`),
        ]
        userLines.push(graphLines.join("\n"))
      }

      const { content } = await callAi(
        buildChatMessages(STUDY_PATH_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.5, maxTokens: 2000 }
      )
      const parsed = extractJson(content)
      const validated = StudyPathResultSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            currentLevel: "Analysis unavailable",
            learningPath: [],
            summary: "Unable to generate learning path at this time.",
            motivation: "Keep learning!",
          },
        }
      }
      return { result: validated.data }
    })
  }

  async explainError(input: ExplainErrorInput): Promise<ExplainErrorResult> {
    return withAiTracking(this.userId, "explain_error", undefined, async () => {
      const userLines = [
        `Question Type: ${input.questionType}`,
        input.subject ? `Subject: ${input.subject}` : "",
        input.knowledgePointIds?.length
          ? `Knowledge Points: ${input.knowledgePointIds.join(", ")}`
          : "",
        `Question:\n${input.questionText}`,
        `Student Answer:\n${input.studentAnswer}`,
        input.correctAnswer ? `Correct Answer:\n${input.correctAnswer}` : "",
      ].filter((line) => line.length > 0)
      const { content } = await callAi(
        buildChatMessages(EXPLAIN_ERROR_SYSTEM_PROMPT, userLines.join("\n\n")),
        { temperature: 0.4, maxTokens: 2000 }
      )
      const parsed = extractJson(content)
      const validated = ExplainErrorResultSchema.safeParse(parsed)
      if (!validated.success) {
        return {
          result: {
            errorAnalysis: "Unable to analyze the error at this time.",
            correctApproach: "Please consult your teacher for help.",
            keyConcepts: [],
            preventionTips: [],
            practiceSuggestion: "Review the relevant chapter and try again.",
          },
        }
      }
      return { result: validated.data }
    })
  }
}

/**
 * 创建 AI 服务实例
 *
 * 在 Server Action 中调用，传入当前用户 ID。
 * 测试时可替换为 mock 实现。
 */
export const createAiService = (userId: string): AiService =>
  new DefaultAiService(userId)

/**
 * 安全执行 AI 调用，捕获异常并返回错误消息
 */
export const safeAiCall = async <T>(
  fn: () => Promise<T>
): Promise<{ ok: true; data: T } | { ok: false; message: string }> => {
  try {
    const data = await fn()
    return { ok: true, data }
  } catch (error) {
    return { ok: false, message: getAiErrorMessage(error) }
  }
}
