/**
 * AI 试卷生成管线（入口模块）
 *
 * 本目录由三个子模块组成：
 * - parse.ts: Zod schema、JSON 解析、纯转换函数、提示词
 * - request.ts: AI 请求构造与发送
 * - structure.ts: 结构生成与预览/草稿转换
 *
 * 本文件负责：
 * - 重新导出公共 API（schema、类型、函数）
 * - 编排高层流程（generateAiPreviewData / generateAiCreateDraftFromSource）
 */

import { z } from "zod"
import { createId } from "@paralleldrive/cuid2"

import {
  AiExamResponseSchema,
  AiQuestionSchema,
  AiInsertQuestionSchema,
  AiGeneratedStructureSchema,
} from "./parse"
import type {
  AiGeneratedQuestion,
  AiGeneratedStructureNode,
} from "./parse"
import {
  parseQuestionDetail,
  requestAiExamDraft,
  requestAiExamStructureDraft,
  validateExamSourceText,
  type SplitQuestionItem,
} from "./request"
import {
  buildPreviewPayload,
  mapWithConcurrency,
  previewToDraft,
  splitStructureItems,
} from "./structure"

// ---------------------------------------------------------------------------
// Re-export public schemas & types
// ---------------------------------------------------------------------------

export {
  AiGeneratedStructureSchema,
  AiGeneratedStructureNodeSchema,
  AiInsertQuestionSchema,
  AiQuestionSchema,
} from "./parse"

export type {
  AiGeneratedQuestion,
  AiGeneratedStructureNode,
  AiPreviewData,
  AiPreviewQuestion,
  AiRewriteQuestionData,
  QuestionContentResult,
} from "./parse"

// ---------------------------------------------------------------------------
// Re-export public functions
// ---------------------------------------------------------------------------

export { regenerateAiQuestionByInstruction } from "./request"

// ---------------------------------------------------------------------------
// High-level orchestration
// ---------------------------------------------------------------------------

export async function generateAiPreviewData(input: {
  title: string
  subject?: string
  grade?: string
  difficulty: number
  totalScore: number
  durationMin: number
  questionCount?: number
  sourceText: string
  aiProviderId?: string
}) {
  const sourceValidation = await validateExamSourceText({
    sourceText: input.sourceText,
    aiProviderId: input.aiProviderId,
  })
  if (!sourceValidation.ok) {
    return { ok: false as const, message: sourceValidation.message }
  }
  const structureDraft = await requestAiExamStructureDraft(input)
  if (!structureDraft.ok) return structureDraft
  const splitItems = splitStructureItems(structureDraft.data)
  const limitedItems = typeof input.questionCount === "number" && input.questionCount > 0
    ? splitItems.slice(0, input.questionCount)
    : splitItems
  if (limitedItems.length === 0) {
    return { ok: false as const, message: "AI returned no questions" }
  }
  const detailedQuestions = await mapWithConcurrency(limitedItems, 6, (item) => parseQuestionDetail({
    item,
    subject: input.subject,
    grade: input.grade,
    difficulty: input.difficulty,
    aiProviderId: input.aiProviderId,
  }))
  const hasSectionStructure = limitedItems.some((item: SplitQuestionItem) => item.sectionIndex !== null)
  const aiParsed: z.infer<typeof AiExamResponseSchema> = hasSectionStructure
    ? {
      title: structureDraft.data.title ?? input.title,
      sections: (() => {
        const sectionMap = new Map<number, { title: string; questions: z.infer<typeof AiQuestionSchema>[] }>()
        limitedItems.forEach((item, index) => {
          if (item.sectionIndex === null) return
          const existed = sectionMap.get(item.sectionIndex)
          const question = detailedQuestions[index]
          if (existed) {
            existed.questions.push(question)
            return
          }
          sectionMap.set(item.sectionIndex, {
            title: item.sectionTitle || `Section ${item.sectionIndex + 1}`,
            questions: [question],
          })
        })
        return Array.from(sectionMap.entries())
          .sort((a, b) => a[0] - b[0])
          .map(([, section]) => section)
      })(),
      questions: undefined,
    }
    : {
      title: structureDraft.data.title ?? input.title,
      questions: detailedQuestions,
      sections: undefined,
    }
  const payload = buildPreviewPayload(aiParsed, input)
  return {
    ok: true as const,
    data: payload,
    rawOutput: structureDraft.rawOutput,
  }
}

export async function generateAiCreateDraftFromSource(input: {
  title: string
  subject?: string
  grade?: string
  difficulty: number
  totalScore: number
  durationMin: number
  questionCount?: number
  sourceText: string
  aiProviderId?: string
}) {
  const preview = await generateAiPreviewData(input)
  if (!preview.ok) {
    return preview
  }
  const draft = previewToDraft(preview.data)
  return {
    ok: true as const,
    generated: draft.generated,
    structure: draft.structure,
    rawOutput: preview.rawOutput,
  }
}

export async function generateAiExamDraft(input: {
  title?: string
  subject?: string
  grade?: string
  difficulty?: number
  totalScore?: number
  durationMin?: number
  questionCount?: number
  sourceText: string
  aiProviderId?: string
}) {
  return requestAiExamDraft(input)
}

// ---------------------------------------------------------------------------
// AI 草稿加载辅助（从 exams/actions.ts 下沉）
// ---------------------------------------------------------------------------

/**
 * 加载 AI 草稿题目与结构：优先从 rawAiQuestions 解析预览 payload，否则从源文本生成。
 */
export async function loadAiDraftQuestionsAndStructure(input: {
  rawAiQuestions: string | null
  rawStructure: string | null
  title: string
  subject: string
  grade: string
  difficulty: number
  totalScore: number
  durationMin: number
  aiSourceText?: string
  aiQuestionCount?: number
  aiProviderId?: string
}): Promise<
  | { ok: true; generated: AiGeneratedQuestion[]; structure: AiGeneratedStructureNode[] }
  | { ok: false; message: string }
> {
  if (input.rawAiQuestions) {
    let parsedQuestions: unknown = null
    try {
      parsedQuestions = JSON.parse(input.rawAiQuestions)
    } catch {
      return { ok: false, message: "Invalid AI preview payload" }
    }
    const validated = z.array(AiInsertQuestionSchema).safeParse(parsedQuestions)
    if (!validated.success || validated.data.length === 0) {
      return { ok: false, message: "Invalid AI preview payload" }
    }
    const generated: AiGeneratedQuestion[] = validated.data.map((q) => ({
      id: q.id,
      type: q.type,
      difficulty: q.difficulty,
      score: q.score,
      content: {
        text: q.content.text,
        ...(q.content.options
          ? {
              options: q.content.options.map((opt) => ({
                id: opt.id,
                text: opt.text,
                isCorrect: opt.isCorrect ?? false,
              })),
            }
          : {}),
        ...(q.content.subQuestions ? { subQuestions: q.content.subQuestions } : {}),
      },
    }))
    let structure: AiGeneratedStructureNode[] = []
    if (input.rawStructure) {
      try {
        const parsedStructure = JSON.parse(input.rawStructure)
        const validatedStructure = AiGeneratedStructureSchema.safeParse(parsedStructure)
        if (validatedStructure.success) {
          structure = validatedStructure.data
        } else {
          return { ok: false, message: "Invalid preview structure" }
        }
      } catch {
        return { ok: false, message: "Invalid preview structure" }
      }
    }
    if (structure.length === 0) {
      structure = generated.map((q) => ({
        id: createId(),
        type: "question",
        questionId: q.id,
        score: q.score,
      }))
    }
    return { ok: true, generated, structure }
  }

  const sourceText = input.aiSourceText?.trim()
  if (!sourceText) {
    return { ok: false, message: "Please analyze and preview before creating" }
  }
  const aiDraft = await generateAiCreateDraftFromSource({
    title: input.title,
    subject: input.subject,
    grade: input.grade,
    difficulty: input.difficulty,
    totalScore: input.totalScore,
    durationMin: input.durationMin,
    questionCount: input.aiQuestionCount,
    sourceText,
    aiProviderId: input.aiProviderId,
  })
  if (!aiDraft.ok) {
    return { ok: false, message: aiDraft.message }
  }
  return { ok: true, generated: aiDraft.generated, structure: aiDraft.structure }
}
