import { randomUUID } from "crypto"
import { NextRequest, NextResponse } from "next/server"
import { getMedicalIcon } from "@/lib/medical-icons"
import { prisma } from "@/lib/prisma"
import {
  contentAuditCreateData,
  contentAuditCategoryInclude,
  requireContentAuditActor,
} from "@/lib/content-audit"
import { resolveUniqueSlug } from "@/lib/category-slug"
import { slugify } from "@/lib/slugify"
import {
  CATEGORY_ENTITY_TYPE,
  CATEGORY_LOCALES,
  descriptionFromBody,
  categoryRelationCountsFromRow,
  toCategoryApiRecord,
  type CategoryLocale,
} from "@/lib/category-db"
import type { CategoriesListResponse, CategoryMutationResponse, CategoryErrorResponse } from "@/types/category-api"

export const dynamic = "force-dynamic"
export const revalidate = 0

const NO_CACHE_HEADERS = {
  "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
  Pragma: "no-cache",
  Expires: "0",
}

type TranslationInput = {
  name: string
  description: string | null
}

function parseLocale(raw: string | null): CategoryLocale {
  if (raw === "ar" || raw === "tr" || raw === "en") return raw
  return "en"
}

function parseTranslationInput(value: unknown): TranslationInput {
  if (!value || typeof value !== "object") {
    return { name: "", description: null }
  }
  const v = value as Record<string, unknown>
  return {
    name: typeof v.name === "string" ? v.name.trim() : "",
    description: descriptionFromBody(v.description),
  }
}

function isSchemaDriftError(err: unknown): boolean {
  if (err && typeof err === "object" && "code" in err && (err as { code?: string }).code === "P2022") {
    return true
  }
  const message = err instanceof Error ? err.message : ""
  return /unknown column|createdbyid|updatedbyid/i.test(message)
}

function parsePayloadTranslations(json: Record<string, unknown>) {
  const translationsRoot =
    json.translations && typeof json.translations === "object"
      ? (json.translations as Record<string, unknown>)
      : {}
  const en = parseTranslationInput(translationsRoot.en)
  const ar = parseTranslationInput(translationsRoot.ar)
  const tr = parseTranslationInput(translationsRoot.tr)

  if (!en.name) {
    en.name = typeof json.name === "string" ? json.name.trim() : ""
    if (en.description === null) {
      en.description = descriptionFromBody(json.description)
    }
  }

  return { en, ar, tr }
}

export async function GET(req: NextRequest) {
  try {
    const locale = parseLocale(req.nextUrl.searchParams.get("locale"))
    let rows: Array<{
      id: string
      name: string
      slug: string
      description: string | null
      color: string
      iconKey: string | null
      isVisible: boolean
      createdAt: Date
      updatedAt: Date
      _count: { Article: number; Doctor: number; Hospital: number; Procedure: number }
      createdBy?: { id: string; name: string | null; email: string; image: string | null } | null
      updatedBy?: { id: string; name: string | null; email: string; image: string | null } | null
    }> = []

    try {
      rows = await prisma.category.findMany({
        orderBy: { updatedAt: "desc" },
        include: {
          _count: { select: { Article: true, Doctor: true, Hospital: true, Procedure: true } },
          ...contentAuditCategoryInclude,
        },
      })
    } catch (err) {
      if (!isSchemaDriftError(err)) {
        console.warn("[categories] primary query failed, trying compatibility fallback:", err)
      }
      rows = await prisma.category.findMany({
        orderBy: { updatedAt: "desc" },
        include: {
          _count: { select: { Article: true, Doctor: true, Hospital: true, Procedure: true } },
        },
      })
    }

    const categoryIds = rows.map((row) => row.id)
    const translationRows = categoryIds.length
      ? await prisma.translation.findMany({
          where: { entityType: CATEGORY_ENTITY_TYPE, entityId: { in: categoryIds } },
          select: { entityId: true, locale: true, name: true, description: true },
        })
      : []
    const byCategoryId = new Map<string, typeof translationRows>()
    for (const tr of translationRows) {
      const bucket = byCategoryId.get(tr.entityId)
      if (bucket) bucket.push(tr)
      else byCategoryId.set(tr.entityId, [tr])
    }
    const body: CategoriesListResponse = {
      categories: rows.map((row) =>
        toCategoryApiRecord(
          row,
          categoryRelationCountsFromRow(row),
          locale,
          byCategoryId.get(row.id) ?? []
        )
      ),
    }
    return NextResponse.json(body, { headers: NO_CACHE_HEADERS })
  } catch (err) {
    console.error("[categories] GET error:", err)
    return NextResponse.json<CategoryErrorResponse>(
      { error: "Failed to load categories" },
      { status: 500 }
    )
  }
}

export async function POST(req: NextRequest) {
  try {
    const auth = await requireContentAuditActor()
    if (!auth.ok) {
      return NextResponse.json<CategoryErrorResponse>({ error: "Unauthorized" }, { status: 401 })
    }

    const json = await req.json().catch(() => null)
    if (!json || typeof json !== "object") {
      return NextResponse.json<CategoryErrorResponse>({ error: "Invalid JSON body" }, { status: 400 })
    }

    const payload = json as Record<string, unknown>
    const translations = parsePayloadTranslations(payload)
    const englishName = translations.en.name
    const slugInput = typeof json.slug === "string" ? json.slug : ""
    const color = typeof json.color === "string" ? json.color.trim() : ""
    const iconKeyInput = typeof json.iconKey === "string" ? json.iconKey.trim() : ""
    const iconKey = iconKeyInput && getMedicalIcon(iconKeyInput) ? iconKeyInput : null
    const isVisible =
      typeof json.isVisible === "boolean" ? json.isVisible : true

    const fieldErrors: Record<string, string> = {}
    if (!englishName) fieldErrors["translations.en.name"] = "English name is required"
    if (!slugInput.trim()) fieldErrors.slug = "Slug is required"
    if (!color) fieldErrors.color = "Color is required"

    if (Object.keys(fieldErrors).length) {
      return NextResponse.json<CategoryErrorResponse>(
        { error: "Validation failed", fieldErrors },
        { status: 400 }
      )
    }

    const slugBase = slugify(slugInput) || slugify(englishName) || "category"
    const slug = await resolveUniqueSlug(slugBase)

    const nameTaken = await prisma.category.findFirst({
      where: {
        name: englishName,
      },
      select: { id: true },
    })
    if (nameTaken) {
      return NextResponse.json<CategoryErrorResponse>(
        { error: "A category with this name already exists", fieldErrors: { name: "Duplicate name" } },
        { status: 409 }
      )
    }

    const createdId = await prisma.$transaction(
      async (tx) => {
        const now = new Date()
        const created = await tx.category.create({
          data: {
            id: randomUUID(),
            name: englishName,
            slug,
            description: translations.en.description,
            color,
            iconKey,
            isVisible,
            ...contentAuditCreateData(auth.user.id),
          },
        })

        const translationRows = CATEGORY_LOCALES
          .map((locale) => ({ locale, data: translations[locale] }))
          .filter(({ locale, data }) => locale === "en" || data.name || data.description)
          .map(({ locale, data }) => ({
            id: randomUUID(),
            updatedAt: now,
            entityType: CATEGORY_ENTITY_TYPE,
            entityId: created.id,
            locale,
            name: data.name || null,
            description: data.description,
          }))

        if (translationRows.length > 0) {
          await tx.translation.createMany({ data: translationRows })
        }

        return created.id
      },
      { maxWait: 15_000, timeout: 60_000 }
    )

    const saved = await prisma.category.findUnique({
      where: { id: createdId },
      include: {
        _count: { select: { Article: true, Doctor: true, Hospital: true, Procedure: true } },
        ...contentAuditCategoryInclude,
      },
    })
    if (!saved) {
      return NextResponse.json<CategoryErrorResponse>(
        { error: "Failed to create category" },
        { status: 500 }
      )
    }
    const createdTranslations = await prisma.translation.findMany({
      where: { entityType: CATEGORY_ENTITY_TYPE, entityId: createdId },
      select: { locale: true, name: true, description: true },
    })

    const body: CategoryMutationResponse = {
      category: toCategoryApiRecord(saved, categoryRelationCountsFromRow(saved), "en", createdTranslations),
    }
    return NextResponse.json(body, { status: 201 })
  } catch (err) {
    console.error("[categories] POST error:", err)
    return NextResponse.json<CategoryErrorResponse>(
      { error: "Failed to create category" },
      { status: 500 }
    )
  }
}
