import { randomUUID } from "crypto"
import { NextRequest, NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
import type { Hospital_status } from "@prisma/client"
import {
  buildContentAudit,
  contentAuditCreateData,
  contentAuditHospitalInclude,
  requireContentAuditActor,
} from "@/lib/content-audit"
import {
  HOSPITAL_LOCALES,
  HOSPITAL_SECTION_KEYS,
  normalizeHospitalSharedImages,
  parseHospitalLocale,
  sanitizePersistedHospitalSections,
} from "@/lib/hospital-db"
import { validateUrlSlug } from "@/lib/slug-validation"
import { getPersistedMediaValidationError } from "@/lib/media-manager/validate-persisted-payload"

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

function fail(message: string, status = 400) {
  return NextResponse.json({ success: false as const, error: message }, { status })
}

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 parseString(value: unknown): string {
  return typeof value === "string" ? value.trim() : ""
}

function parseNumber(value: unknown): number {
  const n = typeof value === "number" ? value : Number(value)
  return Number.isFinite(n) ? n : 0
}

function parseOptionalFoundedYear(value: unknown): number | null {
  if (value === "" || value === null || value === undefined) return null
  const raw = typeof value === "string" ? value.trim() : value
  if (raw === "") return null
  const n = typeof raw === "number" ? raw : Number(raw)
  if (!Number.isFinite(n)) return null
  const y = Math.trunc(n)
  const maxY = new Date().getFullYear() + 1
  if (y < 1800 || y > maxY) return null
  return y
}

function parseNonNegativeInt(value: unknown): number {
  const n = typeof value === "number" ? value : Number(value)
  if (!Number.isFinite(n) || n < 0) return 0
  return Math.trunc(n)
}

function parseJsonOr<T>(value: string | null | undefined, fallback: T): T {
  if (!value) return fallback
  try {
    return JSON.parse(value) as T
  } catch {
    return fallback
  }
}

function toJson(value: unknown): string {
  return JSON.stringify(value ?? {})
}

function buildLocaleSections(source: Record<string, unknown>): Record<string, unknown> {
  const out: Record<string, unknown> = {}
  for (const key of HOSPITAL_SECTION_KEYS) out[key] = source[key] ?? {}
  return out
}

function hasMeaningfulContent(value: unknown): boolean {
  if (value === null || value === undefined) return false
  if (typeof value === "string") return value.trim() !== ""
  if (typeof value === "number" || typeof value === "boolean") return true
  if (Array.isArray(value)) return value.some((item) => hasMeaningfulContent(item))
  if (typeof value === "object") {
    return Object.values(value as Record<string, unknown>).some((item) => hasMeaningfulContent(item))
  }
  return false
}

function toSummaryHospital(row: {
  id: string
  name: string
  image: string
  rating: number
  reviewCount: number
  status: Hospital_status
  createdAt: Date
  updatedAt: Date
  isFeatured: boolean
  location: string
  foundedYear: number | null
  bedsCount: number
  departmentsCount: number
  doctorsCount: number
  patientsPerYear: number
  Category?: { name: string; color: string } | null
  createdBy?: { id: string; name: string | null; email: string; image: string | null } | null
  updatedBy?: { id: string; name: string | null; email: string; image: string | null } | null
}) {
  return {
    id: row.id,
    name: row.name,
    image: row.image,
    rating: row.rating,
    reviewCount: row.reviewCount,
    status: row.status,
    isFeatured: row.isFeatured,
    location: row.location,
    foundedYear: row.foundedYear ?? null,
    bedsCount: row.bedsCount,
    departmentsCount: row.departmentsCount,
    doctorsCount: row.doctorsCount,
    patientsPerYear: row.patientsPerYear,
    category: row.Category
      ? { name: row.Category.name, color: row.Category.color }
      : null,
    audit: buildContentAudit(row),
  }
}

export async function GET(req: NextRequest) {
  try {
    const locale = parseHospitalLocale(req.nextUrl.searchParams.get("locale"))
    let rows: Array<{
      id: string
      slug: string
      name: string
      image: string
      rating: number
      reviewCount: number
      status: Hospital_status
      createdAt: Date
      updatedAt: Date
      isFeatured: boolean
      location: string
      foundedYear: number | null
      bedsCount: number
      departmentsCount: number
      doctorsCount: number
      patientsPerYear: number
      heroJson: string
      locationJson: string
      Category?: { id: string; name: string; color: string }
      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.hospital.findMany({
        orderBy: { updatedAt: "desc" },
        include: {
          Category: { select: { id: true, name: true, color: true } },
          ...contentAuditHospitalInclude,
        },
      })
    } catch (err) {
      if (!isSchemaDriftError(err)) {
        console.warn("[hospitals] primary query failed, trying compatibility fallback:", err)
      }
      rows = await prisma.hospital.findMany({
        orderBy: { updatedAt: "desc" },
        include: {
          Category: { select: { id: true, name: true, color: true } },
        },
      })
    }

    const ids = rows.map((row) => row.id)
    const trRows = ids.length
      ? await prisma.hospitalTranslation.findMany({
          where: { hospitalId: { in: ids }, locale },
          select: { hospitalId: true, locale: true, name: true, location: true, heroJson: true, locationJson: true },
        })
      : []
    const byHospital = new Map<string, (typeof trRows)[number]>()
    for (const tr of trRows) byHospital.set(tr.hospitalId, tr)

    return NextResponse.json(
      {
        success: true as const,
        hospitals: rows.map((row) => {
          const tr = byHospital.get(row.id)
          const hero = parseJsonOr<Record<string, unknown>>(tr?.heroJson ?? row.heroJson, {})
          const locationSection = parseJsonOr<Record<string, unknown>>(tr?.locationJson ?? row.locationJson, {})
          return {
            ...toSummaryHospital(row),
            slug: row.slug,
            name: parseString(tr?.name) || parseString(hero.title) || row.name,
            location: parseString(tr?.location) || parseString(locationSection.title) || row.location,
          }
        }),
      },
      { headers: NO_CACHE_HEADERS }
    )
  } catch (err) {
    console.error("[hospitals] GET error:", err)
    return NextResponse.json({ success: false as const, error: "Failed to load hospitals" }, { status: 500 })
  }
}

export async function POST(req: NextRequest) {
  try {
    const auth = await requireContentAuditActor()
    if (!auth.ok) return auth.response

    const payload = (await req.json()) as Record<string, unknown>
    const mediaError = getPersistedMediaValidationError(payload)
    if (mediaError) return fail(mediaError)

    const status: Hospital_status = payload.status === "draft" ? "draft" : "published"

    const categoryId = parseString(payload.categoryId)
    const basicInfo =
      payload.basicInfo && typeof payload.basicInfo === "object"
        ? (payload.basicInfo as Record<string, unknown>)
        : {}
    const translationsInput =
      payload.translations && typeof payload.translations === "object"
        ? (payload.translations as Record<string, unknown>)
        : {}
    const translations = normalizeHospitalSharedImages(translationsInput) as Record<string, unknown>
    const enPayload =
      translations.en && typeof translations.en === "object" ? (translations.en as Record<string, unknown>) : {}
    const enSections = sanitizePersistedHospitalSections(
      buildLocaleSections(
        translations.en && typeof translations.en === "object" ? (translations.en as Record<string, unknown>) : {}
      )
    )

    const slug = parseString(basicInfo.slug)
    const name = parseString(enPayload.hospitalName)
    const type = parseString(enPayload.hospitalType)
    const image = parseString(basicInfo.image)
    const imagePublicId = parseString(basicInfo.imagePublicId)
    const rating = parseNumber(basicInfo.rating)
    const reviewCount = Math.max(0, Math.trunc(parseNumber(basicInfo.reviewCount)))
    const foundedYear = parseOptionalFoundedYear(basicInfo.foundedYear)
    const bedsCount = parseNonNegativeInt(basicInfo.bedsCount)
    const departmentsCount = parseNonNegativeInt(basicInfo.departmentsCount)
    const doctorsCount = parseNonNegativeInt(basicInfo.doctorsCount)
    const patientsPerYear = parseNonNegativeInt(basicInfo.patientsPerYear)
    const isFeatured = Boolean(basicInfo.isFeatured)
    const location = parseString(enPayload.hospitalLocation)

    if (!slug) return fail("Slug is required")
    const slugValidation = validateUrlSlug(slug)
    if (!slugValidation.valid) return fail(slugValidation.error ?? "Invalid slug")

    if (categoryId) {
      const category = await prisma.category.findUnique({ where: { id: categoryId }, select: { id: true } })
      if (!category) return fail("Selected category does not exist")
    }

    const existingSlug = await prisma.hospital.findUnique({ where: { slug }, select: { id: true } })
    if (existingSlug) return fail("Slug already in use", 409)

    const now = new Date()
    const hospital = await prisma.hospital.create({
      data: {
        id: randomUUID(),
        categoryId: categoryId || (await prisma.category.findFirst({ select: { id: true }, orderBy: { createdAt: "asc" } }))?.id || "",
        slug,
        name: name || "Untitled Hospital Draft",
        type,
        image,
        imagePublicId,
        rating,
        reviewCount,
        foundedYear,
        bedsCount,
        departmentsCount,
        doctorsCount,
        patientsPerYear,
        location,
        isFeatured,
        status,
        heroJson: toJson(enSections.hero),
        aboutJson: toJson(enSections.about),
        galleryJson: toJson(enSections.gallery),
        departmentsJson: toJson(enSections.departments),
        doctorsJson: toJson(enSections.doctors),
        accreditationJson: toJson(enSections.accreditation),
        technologyJson: toJson(enSections.technology),
        visitProcessJson: toJson(enSections.visitProcess),
        reviewsJson: toJson(enSections.reviews),
        locationJson: toJson(enSections.location),
        packagesJson: toJson(enSections.packages),
        faqJson: toJson(enSections.faq),
        ctaJson: toJson(enSections.cta),
        similarJson: toJson(enSections.similar),
        ...contentAuditCreateData(auth.user.id),
      },
      include: {
        Category: { select: { id: true, name: true, color: true } },
        ...contentAuditHospitalInclude,
      },
    })
    const translationRows = HOSPITAL_LOCALES.flatMap((locale) => {
      const localeRawInput =
        translationsInput[locale] && typeof translationsInput[locale] === "object"
          ? (translationsInput[locale] as Record<string, unknown>)
          : {}
      const localeSectionsRaw = sanitizePersistedHospitalSections(buildLocaleSections(localeRawInput))
      const localizedNameRaw =
        typeof localeRawInput.hospitalName === "string" ? localeRawInput.hospitalName.trim() : ""
      const localizedLocationRaw =
        typeof localeRawInput.hospitalLocation === "string" ? localeRawInput.hospitalLocation.trim() : ""
      const localizedHospitalTypeRaw =
        typeof localeRawInput.hospitalType === "string" ? localeRawInput.hospitalType.trim() : ""
      if (
        locale !== "en" &&
        !hasMeaningfulContent({
          ...localeSectionsRaw,
          localizedName: localizedNameRaw,
          localizedLocation: localizedLocationRaw,
          localizedHospitalType: localizedHospitalTypeRaw,
        })
      ) {
        return []
      }

      const localeRaw =
        translations[locale] && typeof translations[locale] === "object"
          ? (translations[locale] as Record<string, unknown>)
          : {}
      const localeSections = sanitizePersistedHospitalSections(buildLocaleSections(localeRaw))
      const localizedName = typeof localeRaw.hospitalName === "string" ? localeRaw.hospitalName.trim() : ""
      const localizedLocation =
        typeof localeRaw.hospitalLocation === "string" ? localeRaw.hospitalLocation.trim() : ""
      const localizedHospitalType =
        typeof localeRaw.hospitalType === "string" ? localeRaw.hospitalType.trim() : ""

      return [{
        id: randomUUID(),
        updatedAt: now,
        hospitalId: hospital.id,
        locale,
        name: localizedName || (locale === "en" ? (name || null) : null),
        location: localizedLocation || (locale === "en" ? (location || null) : null),
        hospitalType: localizedHospitalType ? localizedHospitalType : null,
        heroJson: toJson(localeSections.hero),
        aboutJson: toJson(localeSections.about),
        galleryJson: toJson(localeSections.gallery),
        departmentsJson: toJson(localeSections.departments),
        doctorsJson: toJson(localeSections.doctors),
        accreditationJson: toJson(localeSections.accreditation),
        technologyJson: toJson(localeSections.technology),
        visitProcessJson: toJson(localeSections.visitProcess),
        reviewsJson: toJson(localeSections.reviews),
        locationJson: toJson(localeSections.location),
        packagesJson: toJson(localeSections.packages),
        faqJson: toJson(localeSections.faq),
        ctaJson: toJson(localeSections.cta),
        similarJson: toJson(localeSections.similar),
      }]
    })
    await prisma.hospitalTranslation.createMany({ data: translationRows })

    return NextResponse.json(
      {
        success: true as const,
        hospital: {
          ...toSummaryHospital(hospital),
          slug: hospital.slug,
        },
      },
      { status: 201 }
    )
  } catch (err) {
    console.error("[hospitals] POST error:", err)
    return NextResponse.json({ success: false as const, error: "Internal server error" }, { status: 500 })
  }
}
