import { NextResponse } from "next/server"
import { createId } from "@paralleldrive/cuid2"
import { mkdir, writeFile } from "fs/promises"
import path from "path"

import { requireAuth } from "@/shared/lib/auth-guard"
import {
  generateStoragePath,
  isAllowedMimeType,
  MAX_FILE_SIZE,
} from "@/shared/lib/file-storage"
import { rateLimit, rateLimitKey, rateLimitHeaders, RATE_LIMIT_RULES } from "@/shared/lib/rate-limit"
import { createFileAttachment } from "@/modules/files/data-access"
import type { FileTargetType } from "@/modules/files/types"

export const dynamic = "force-dynamic"

const VALID_TARGET_TYPES: FileTargetType[] = [
  "exam",
  "textbook",
  "question",
  "announcement",
]

const isTargetType = (v: string | null): v is FileTargetType =>
  v !== null && (VALID_TARGET_TYPES as readonly string[]).includes(v)

export async function POST(req: Request) {
  try {
    const ctx = await requireAuth()
    const uploaderId = ctx.userId

    // Rate limit uploads per user
    const limitKey = rateLimitKey("upload", uploaderId)
    const limit = rateLimit({ key: limitKey, ...RATE_LIMIT_RULES.UPLOAD })
    if (!limit.success) {
      return NextResponse.json(
        { success: false, message: "Upload rate limit exceeded. Please try again later." },
        { status: 429, headers: rateLimitHeaders(limit) }
      )
    }

    const formData = await req.formData()
    const file = formData.get("file")
    const targetType = formData.get("targetType")
    const targetId = formData.get("targetId")

    if (!(file instanceof File)) {
      return NextResponse.json(
        { success: false, message: "No file provided" },
        { status: 400 }
      )
    }

    if (file.size === 0) {
      return NextResponse.json(
        { success: false, message: "File is empty" },
        { status: 400 }
      )
    }

    if (file.size > MAX_FILE_SIZE) {
      return NextResponse.json(
        { success: false, message: "File size exceeds 10MB limit" },
        { status: 413 }
      )
    }

    const mimeType = file.type || "application/octet-stream"
    if (!isAllowedMimeType(mimeType)) {
      return NextResponse.json(
        { success: false, message: `File type ${mimeType} is not allowed` },
        { status: 415 }
      )
    }

    const originalName = file.name || "unnamed"
    const storagePath = generateStoragePath(originalName)
    const absoluteDir = path.join(process.cwd(), "public", path.dirname(storagePath))
    await mkdir(absoluteDir, { recursive: true })

    const bytes = Buffer.from(await file.arrayBuffer())
    const absolutePath = path.join(process.cwd(), "public", storagePath)
    await writeFile(absolutePath, bytes)

    const url = `/${storagePath}`
    const id = createId()
    const filename = path.basename(storagePath)

    const created = await createFileAttachment({
      id,
      filename,
      originalName,
      mimeType,
      size: file.size,
      storagePath,
      url,
      uploaderId,
      targetType: isTargetType(typeof targetType === "string" ? targetType : null)
        ? (targetType as string)
        : null,
      targetId: typeof targetId === "string" && targetId.length > 0 ? targetId : null,
    })

    if (!created) {
      return NextResponse.json(
        { success: false, message: "Failed to persist file record" },
        { status: 500 }
      )
    }

    return NextResponse.json({
      success: true,
      id: created.id,
      url: created.url,
      filename: created.filename,
      originalName: created.originalName,
      size: created.size,
      mimeType: created.mimeType,
    })
  } catch (e) {
    const message = e instanceof Error ? e.message : "Upload failed"
    const status = message.includes("Permission denied") || message.includes("auth_required")
      ? 401
      : 500
    return NextResponse.json({ success: false, message }, { status })
  }
}
