import { NextRequest } from "next/server"

import { auth } from "@/auth"
import { Permissions } from "@/shared/types/permissions"
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
import { createAiChatCompletionStream } from "@/shared/lib/ai/client"
import { getAiErrorMessage } from "@/shared/lib/ai"
import { trackEvent } from "@/shared/lib/track-event"
import {
  rateLimit,
  rateLimitKey,
  RATE_LIMIT_RULES,
} from "@/shared/lib/rate-limit"
import { env } from "@/env.mjs"

import { CHAT_SYSTEM_PROMPT, SOCRATIC_TUTOR_SYSTEM_PROMPT } from "@/modules/ai/services/prompt-templates"
import {
  filterUserInput,
  filterAiOutput,
  tryConsumeDailyQuota,
  refundDailyQuota,
  validateSocraticOutput,
} from "@/modules/ai/services/content-safety"
import { AiChatInputSchema } from "@/modules/ai/schema"
import type { AiChatMessage } from "@/modules/ai/types"

/**
 * AI 聊天流式端点（SSE）
 *
 * 使用 Server-Sent Events 逐 token 推送 AI 回复，
 * 降低用户感知延迟。
 *
 * 安全策略（与非流式端点一致）：
 * - requirePermission(AI_CHAT) 权限校验
 * - rateLimit 每分钟限流（防高频滥用）
 * - Zod 校验输入（AiChatInputSchema，限制消息数/长度）
 * - tryConsumeDailyQuota 原子化每日限额（防 TOCTOU 竞态）
 * - 输入/输出内容安全过滤
 * - 学生侧 Socratic 模式（服务端强制，忽略客户端 systemPrompt）
 * - 过滤/失败时 refundDailyQuota（不惩罚用户）
 */

const formatEvent = (data: unknown): string => {
  return `data: ${JSON.stringify(data)}\n\n`
}

const formatError = (message: string): string => {
  return formatEvent({ type: "error", message })
}

const FORMAT_DONE = "data: [DONE]\n\n"

export async function POST(request: NextRequest): Promise<Response> {
  const encoder = new TextEncoder()

  try {
    // 1. 权限校验
    const ctx = await requirePermission(Permissions.AI_CHAT)
    const session = await auth()
    const userRole = session?.user?.role ?? "student"
    const isStudent = userRole === "student"

    // 2. Rate limit（与非流式端点一致）
    const limitResult = await rateLimit({
      key: rateLimitKey("ai-chat-stream", ctx.userId),
      ...RATE_LIMIT_RULES.AI_CHAT,
    })
    if (!limitResult.success) {
      return new Response(formatError("Rate limit exceeded"), {
        status: 429,
        headers: { "Content-Type": "text/event-stream" },
      })
    }

    // 3. Zod 校验输入（防止超大 message 导致 token 爆炸）
    const rawBody = await request.json().catch(() => null)
    const parseResult = AiChatInputSchema.safeParse(rawBody)
    if (!parseResult.success) {
      return new Response(formatError("Invalid input"), {
        status: 400,
        headers: { "Content-Type": "text/event-stream" },
      })
    }
    const body = parseResult.data

    // 4. 原子化每日限额检查（防 TOCTOU 竞态）
    const quotaResult = tryConsumeDailyQuota(ctx.userId, userRole)
    if (quotaResult.blocked) {
      return new Response(formatError("Daily limit reached"), {
        status: 429,
        headers: { "Content-Type": "text/event-stream" },
      })
    }

    // 5. 输入安全过滤
    for (const msg of body.messages) {
      if (msg.role === "user") {
        const filterResult = filterUserInput(msg.content, { isStudent })
        if (filterResult.blocked) {
          // 输入被过滤，回退配额
          refundDailyQuota(ctx.userId)
          return new Response(formatError("Input blocked by safety filter"), {
            status: 400,
            headers: { "Content-Type": "text/event-stream" },
          })
        }
      }
    }

    // 6. 构建 system prompt
    //    安全：服务端强制使用系统提示词，忽略客户端传入的 systemPrompt，
    //    防止学生绕过 Socratic 模式获取直接答案。
    const baseSystemPrompt = isStudent
      ? SOCRATIC_TUTOR_SYSTEM_PROMPT
      : CHAT_SYSTEM_PROMPT

    const messages: AiChatMessage[] = [
      { role: "system", content: baseSystemPrompt },
      ...body.messages,
    ]

    // 7. 流式调用 AI
    const stream = new ReadableStream<Uint8Array>({
      async start(controller) {
        const startTime = Date.now()
        let fullContent = ""
        let success = true
        let errorMessage: string | undefined
        let wasFiltered = false

        const safeEnqueue = (text: string): void => {
          // 防止 controller 已关闭时 enqueue 抛错
          try {
            controller.enqueue(encoder.encode(text))
          } catch {
            // controller 已关闭，忽略
          }
        }

        try {
          const aiStream = createAiChatCompletionStream({
            messages: messages.map((m) => ({ role: m.role, content: m.content })),
            model: String(env.AI_MODEL ?? "gpt-4o-mini"),
            temperature: 0.7,
            ...(body.providerId ? { providerId: body.providerId } : {}),
          })

          for await (const chunk of aiStream) {
            fullContent += chunk

            // 输出安全过滤（逐 chunk 检查关键词）
            const outputFilter = filterAiOutput(chunk, { isStudent })
            if (outputFilter.blocked) {
              safeEnqueue(formatEvent({
                type: "filtered",
                message: "Content filtered for safety",
              }))
              success = false
              wasFiltered = true
              break
            }

            safeEnqueue(formatEvent({ type: "token", content: chunk }))
          }

          // 仅在成功完成时保留配额计数
          // 过滤或失败时回退配额（不惩罚用户）
          if (!success || wasFiltered) {
            refundDailyQuota(ctx.userId)
          }

          // 学生侧：苏格拉底式辅导输出校验
          // 流式完成后检查完整回复是否符合引导式教学原则
          if (success && !wasFiltered && isStudent && fullContent) {
            const socraticResult = validateSocraticOutput(fullContent)
            if (!socraticResult.valid) {
              safeEnqueue(formatEvent({
                type: "socratic_warning",
                message: "AI response did not fully follow Socratic tutoring principles.",
              }))
            }
          }

          safeEnqueue(FORMAT_DONE)
        } catch (error) {
          success = false
          errorMessage = error instanceof Error ? error.message : String(error)
          // AI 调用失败，回退配额
          refundDailyQuota(ctx.userId)
          safeEnqueue(formatError(getAiErrorMessage(error)))
        } finally {
          try {
            controller.close()
          } catch {
            // 已关闭，忽略
          }

          // 埋点
          void trackEvent({
            event: "ai.chat_stream",
            userId: ctx.userId,
            targetType: "chat",
            properties: {
              success,
              durationMs: Date.now() - startTime,
              tokenCount: fullContent.length / 4,
              errorMessage,
              isStudent,
              filtered: wasFiltered,
            },
          }).catch(() => {
            // 静默失败
          })
        }
      },
    })

    return new Response(stream, {
      headers: {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache, no-transform",
        Connection: "keep-alive",
      },
    })
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return new Response(formatError("Permission denied"), {
        status: 403,
        headers: { "Content-Type": "text/event-stream" },
      })
    }
    return new Response(formatError(getAiErrorMessage(error)), {
      status: 500,
      headers: { "Content-Type": "text/event-stream" },
    })
  }
}
