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

type CategoryTranslationRow = {
  locale: CategoryLocale
  name: string | null
  description: string | null
}
import type { CategoryMutationResponse, CategoryErrorResponse } from "@/types/category-api"

type RouteContext = { params: Promise<{ id: string }> }

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),
  }
}

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

    const { id } = await context.params
    if (!id) {
      return NextResponse.json<CategoryErrorResponse>({ error: "Missing id" }, { status: 400 })
    }

    const existing = await prisma.category.findUnique({ where: { id } })
    if (!existing) {
      return NextResponse.json<CategoryErrorResponse>({ error: "Category not found" }, { status: 404 })
    }
    const existingTranslations = (await prisma.translation.findMany({
      where: { entityType: CATEGORY_ENTITY_TYPE, entityId: id },
      select: { locale: true, name: true, description: true },
    })) as CategoryTranslationRow[]

    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 translationsRoot =
      payload.translations && typeof payload.translations === "object"
        ? (payload.translations as Record<string, unknown>)
        : {}
    const enInput = parseTranslationInput(translationsRoot.en)
    const arInput = parseTranslationInput(translationsRoot.ar)
    const trInput = parseTranslationInput(translationsRoot.tr)
    const existingEn = existingTranslations.find((t) => t.locale === "en")
    const englishName =
      enInput.name ||
      (typeof payload.name === "string" ? payload.name.trim() : "") ||
      (existingEn?.name?.trim() ?? "") ||
      existing.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 englishDescription =
      enInput.description ??
      (json.description === undefined ? null : descriptionFromBody(json.description)) ??
      existingEn?.description ??
      existing.description
    const isVisible =
      typeof json.isVisible === "boolean" ? json.isVisible : existing.isVisible

    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 =
      slugBase === existing.slug
        ? existing.slug
        : await resolveUniqueSlug(slugBase, id)

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

    await prisma.$transaction(
      async (tx) => {
        const translationNow = new Date()
        await tx.category.update({
          where: { id },
          data: {
            name: englishName,
            slug,
            description: englishDescription,
            color,
            iconKey,
            isVisible,
            ...contentAuditUpdateData(auth.user.id),
          },
        })

        const payloadByLocale = {
          en: { name: englishName, description: englishDescription },
          ar: arInput,
          tr: trInput,
        }

        for (const locale of CATEGORY_LOCALES) {
          const data = payloadByLocale[locale]
          if (locale !== "en" && !data.name && !data.description) {
            await tx.translation.deleteMany({
              where: { entityType: CATEGORY_ENTITY_TYPE, entityId: id, locale },
            })
            continue
          }
          await tx.translation.upsert({
            where: {
              entityType_entityId_locale: {
                entityType: CATEGORY_ENTITY_TYPE,
                entityId: id,
                locale,
              },
            },
            update: {
              ...touchUpdatedAt(),
              name: data.name || null,
              description: data.description,
            },
            create: {
              id: randomUUID(),
              updatedAt: translationNow,
              entityType: CATEGORY_ENTITY_TYPE,
              entityId: id,
              locale,
              name: data.name || null,
              description: data.description,
            },
          })
        }
      },
      { maxWait: 15_000, timeout: 60_000 }
    )

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

    const locale = parseLocale(req.nextUrl.searchParams.get("locale"))
    const body: CategoryMutationResponse = {
      category: toCategoryApiRecord(saved, categoryRelationCountsFromRow(saved), locale, updatedTranslations),
    }
    return NextResponse.json(body)
  } catch (err) {
    console.error("[categories] PUT error:", err)
    return NextResponse.json<CategoryErrorResponse>(
      { error: "Failed to update category" },
      { status: 500 }
    )
  }
}

export async function DELETE(_req: NextRequest, context: RouteContext) {
  try {
    const { id } = await context.params
    if (!id) {
      return NextResponse.json<CategoryErrorResponse>({ error: "Missing id" }, { status: 400 })
    }

    const result = await prisma.$transaction(async (tx: any) => {
      await tx.translation.deleteMany({
        where: {
          entityType: CATEGORY_ENTITY_TYPE,
          entityId: id,
        },
      })
      return tx.category.deleteMany({ where: { id } })
    })
    if (result.count === 0) {
      return NextResponse.json<CategoryErrorResponse>({ error: "Category not found" }, { status: 404 })
    }

    return new NextResponse(null, { status: 204 })
  } catch (err) {
    console.error("[categories] DELETE error:", err)
    return NextResponse.json<CategoryErrorResponse>(
      { error: "Failed to delete category" },
      { status: 500 }
    )
  }
}
