import { stripRemovedProcedureCtaFields } from "@/lib/procedure-cta-contact-form-defaults"
import type { ProcedureLocale } from "@/lib/procedure-db"

export type LocalizedBasicInfo = {
  startingFromPrice: string
  duration: string
  hospitalStay: string
  recovery: string
}

export type PublicProcedureLocalePayload = {
  name: string
  description: string
  /** Localized stay city (same semantic as dashboard “City Name”); not nested under `doctorsSection` in public API responses. */
  stayCity: string
  basicInfo: LocalizedBasicInfo
  overview: unknown
  countriesComparison: unknown
  process: unknown
  benefits: unknown
  beforeAfterSection: unknown
  doctorsSection: Record<string, unknown>
  recovery: unknown
  packageSection: unknown
  reviewsSection: unknown
  faqSection: unknown
  related: unknown
  cta: unknown
  videoSection: unknown
}

function parseString(value: unknown): string {
  return typeof value === "string" ? value.trim() : ""
}

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 defaultLocalizedBasicInfo(): LocalizedBasicInfo {
  return {
    startingFromPrice: "",
    duration: "",
    hospitalStay: "",
    recovery: "",
  }
}

function emptyLocale(): PublicProcedureLocalePayload {
  return {
    name: "",
    description: "",
    stayCity: "",
    basicInfo: defaultLocalizedBasicInfo(),
    overview: {},
    countriesComparison: {},
    process: {},
    benefits: {},
    beforeAfterSection: {},
    doctorsSection: {},
    recovery: {},
    packageSection: {},
    reviewsSection: {},
    faqSection: {},
    related: {},
    cta: {},
    videoSection: {},
  }
}

type ProcedureRowLike = {
  name: string
  description: string
  overviewJson: string
  countriesComparisonJson: string
  processJson: string
  benefitsJson: string
  beforeAfterSectionJson: string
  doctorsSectionJson: string
  recoveryJson: string
  packageSectionJson: string
  reviewsSectionJson: string
  faqSectionJson: string
  relatedJson: string
  ctaJson: string
  videoSectionJson: string
  basicInfoJson: string
}

type ProcedureTrRowLike = {
  locale: string
  name: string | null
  description: string | null
  stayCity: string | null
  overviewJson: string | null
  countriesComparisonJson: string | null
  processJson: string | null
  benefitsJson: string | null
  beforeAfterSectionJson: string | null
  doctorsSectionJson: string | null
  recoveryJson: string | null
  packageSectionJson: string | null
  reviewsSectionJson: string | null
  faqSectionJson: string | null
  relatedJson: string | null
  ctaJson: string | null
  videoSectionJson: string | null
  basicInfoJson: string | null
}

/** Strip `stayCity` from doctors JSON so storefront reads city only from `stayCity` / `basicInfo.stayCity`. */
function doctorsSectionPublicShape(doctorsRaw: Record<string, unknown>): Record<string, unknown> {
  const { stayCity: _removed, ...rest } = doctorsRaw
  return rest
}

function resolveStayCityMainRow(row: ProcedureRowLike, doctorsRaw: Record<string, unknown>): string {
  const basicInfo = parseJsonOr(row.basicInfoJson, {} as Record<string, unknown>)
  return parseString(doctorsRaw.stayCity) || parseString(basicInfo.stayCity)
}

function parseLocalizedBasicInfo(value: string | null | undefined): LocalizedBasicInfo {
  const raw = parseJsonOr(value, {} as Record<string, unknown>)
  return {
    startingFromPrice: parseString(raw.startingFromPrice),
    duration: parseString(raw.duration),
    hospitalStay: parseString(raw.hospitalStay),
    recovery: parseString(raw.recovery),
  }
}

function isEmptyLocalizedBasicInfo(info: LocalizedBasicInfo): boolean {
  return (
    !parseString(info.startingFromPrice) &&
    !parseString(info.duration) &&
    !parseString(info.hospitalStay) &&
    !parseString(info.recovery)
  )
}

function pickLocalizedBasicInfo(localized: LocalizedBasicInfo, english: LocalizedBasicInfo): LocalizedBasicInfo {
  return isEmptyLocalizedBasicInfo(localized) ? english : localized
}

function payloadFromMainRow(row: ProcedureRowLike): PublicProcedureLocalePayload {
  const doctorsRaw = parseJsonOr(row.doctorsSectionJson, {} as Record<string, unknown>)
  const stayCity = resolveStayCityMainRow(row, doctorsRaw)
  return {
    name: row.name,
    description: row.description,
    stayCity,
    basicInfo: parseLocalizedBasicInfo(row.basicInfoJson),
    overview: parseJsonOr(row.overviewJson, {}),
    countriesComparison: parseJsonOr(row.countriesComparisonJson, {}),
    process: parseJsonOr(row.processJson, {}),
    benefits: parseJsonOr(row.benefitsJson, {}),
    beforeAfterSection: parseJsonOr(row.beforeAfterSectionJson, {}),
    doctorsSection: doctorsSectionPublicShape(doctorsRaw),
    recovery: parseJsonOr(row.recoveryJson, {}),
    packageSection: parseJsonOr(row.packageSectionJson, {}),
    reviewsSection: parseJsonOr(row.reviewsSectionJson, {}),
    faqSection: parseJsonOr(row.faqSectionJson, {}),
    related: parseJsonOr(row.relatedJson, {}),
    cta: stripRemovedProcedureCtaFields(parseJsonOr(row.ctaJson, {})),
    videoSection: parseJsonOr(row.videoSectionJson, {}),
  }
}

function resolveStayCityTranslationRow(
  row: ProcedureRowLike,
  tr: ProcedureTrRowLike,
  doctorsRaw: Record<string, unknown>,
): string {
  const basicInfo = parseJsonOr(row.basicInfoJson, {} as Record<string, unknown>)
  const fromColumn = parseString(tr.stayCity)
  const fromEmbedded = parseString(doctorsRaw.stayCity)
  const englishFallback = tr.locale === "en" ? parseString(basicInfo.stayCity) : ""
  return fromColumn || fromEmbedded || englishFallback
}

function payloadFromTranslationRow(
  row: ProcedureRowLike,
  tr: ProcedureTrRowLike
): PublicProcedureLocalePayload {
  const doctorsRaw = parseJsonOr(tr.doctorsSectionJson ?? row.doctorsSectionJson, {} as Record<string, unknown>)
  const stayCity = resolveStayCityTranslationRow(row, tr, doctorsRaw)
  return {
    name: parseString(tr.name) || row.name,
    description: parseString(tr.description) || row.description,
    stayCity,
    overview: parseJsonOr(tr.overviewJson ?? row.overviewJson, {}),
    countriesComparison: parseJsonOr(tr.countriesComparisonJson ?? row.countriesComparisonJson, {}),
    process: parseJsonOr(tr.processJson ?? row.processJson, {}),
    benefits: parseJsonOr(tr.benefitsJson ?? row.benefitsJson, {}),
    beforeAfterSection: parseJsonOr(tr.beforeAfterSectionJson ?? row.beforeAfterSectionJson, {}),
    doctorsSection: doctorsSectionPublicShape(doctorsRaw),
    recovery: parseJsonOr(tr.recoveryJson ?? row.recoveryJson, {}),
    packageSection: parseJsonOr(tr.packageSectionJson ?? row.packageSectionJson, {}),
    reviewsSection: parseJsonOr(tr.reviewsSectionJson ?? row.reviewsSectionJson, {}),
    faqSection: parseJsonOr(tr.faqSectionJson ?? row.faqSectionJson, {}),
    related: parseJsonOr(tr.relatedJson ?? row.relatedJson, {}),
    cta: stripRemovedProcedureCtaFields(parseJsonOr(tr.ctaJson ?? row.ctaJson, {})),
    basicInfo: parseLocalizedBasicInfo(tr.basicInfoJson ?? row.basicInfoJson),
    videoSection: parseJsonOr(tr.videoSectionJson ?? row.videoSectionJson, {}),
  }
}

/** Same pattern as `buildDoctorTranslations`: always `en`/`ar`/`tr`; overlay DB rows when present. */
export function buildProcedureTranslationsForPublic(
  row: ProcedureRowLike,
  translationRows: ProcedureTrRowLike[]
): Record<ProcedureLocale, PublicProcedureLocalePayload> {
  const baseEn = payloadFromMainRow(row)
  const out: Record<ProcedureLocale, PublicProcedureLocalePayload> = {
    en: { ...baseEn },
    ar: emptyLocale(),
    tr: emptyLocale(),
  }

  const byLocale = new Map<string, ProcedureTrRowLike>()
  for (const tr of translationRows) {
    if (tr.locale === "en" || tr.locale === "ar" || tr.locale === "tr") {
      byLocale.set(tr.locale, tr)
    }
  }

  const enTr = byLocale.get("en")
  if (enTr) {
    out.en = payloadFromTranslationRow(row, enTr)
  }

  const arTr = byLocale.get("ar")
  if (arTr) {
    out.ar = payloadFromTranslationRow(row, arTr)
  }

  const trTr = byLocale.get("tr")
  if (trTr) {
    out.tr = payloadFromTranslationRow(row, trTr)
  }

  return out
}

/**
 * When `locale` is not English, empty localized JSON sections `{}` are replaced with English so the
 * storefront never renders blank blocks for untranslated locales.
 */
export function mergeProcedureLocaleWithEnglishFallback(
  translations: Record<ProcedureLocale, PublicProcedureLocalePayload>,
  locale: ProcedureLocale,
): PublicProcedureLocalePayload {
  const en = translations.en
  if (locale === "en") return en

  const loc = translations[locale]

  function pick(localized: unknown, english: unknown): unknown {
    if (localized === null || localized === undefined) return english
    if (typeof localized === "object" && !Array.isArray(localized)) {
      if (Object.keys(localized as Record<string, unknown>).length === 0) return english
    }
    return localized
  }

  const doctors = pick(loc.doctorsSection, en.doctorsSection) as Record<string, unknown>

  return {
    name: parseString(loc.name) ? loc.name : en.name,
    description: parseString(loc.description) ? loc.description : en.description,
    stayCity: parseString(loc.stayCity) ? loc.stayCity : en.stayCity,
    overview: pick(loc.overview, en.overview),
    countriesComparison: pick(loc.countriesComparison, en.countriesComparison),
    process: pick(loc.process, en.process),
    benefits: pick(loc.benefits, en.benefits),
    beforeAfterSection: pick(loc.beforeAfterSection, en.beforeAfterSection),
    doctorsSection: { ...doctors },
    recovery: pick(loc.recovery, en.recovery),
    packageSection: pick(loc.packageSection, en.packageSection),
    reviewsSection: pick(loc.reviewsSection, en.reviewsSection),
    faqSection: pick(loc.faqSection, en.faqSection),
    related: pick(loc.related, en.related),
    cta: stripRemovedProcedureCtaFields(pick(loc.cta, en.cta)),
    videoSection: pick(loc.videoSection, en.videoSection),
    basicInfo: pickLocalizedBasicInfo(loc.basicInfo, en.basicInfo),
  }
}

/** Merge canonical `basicInfoJson` with localized title and `stayCity` for the storefront locale. */
export function localizedProcedureBasicInfo(
  basicInfoJson: string,
  primary: PublicProcedureLocalePayload,
): Record<string, unknown> {
  const raw = parseJsonOr(basicInfoJson, {} as Record<string, unknown>)
  const localizedStay = parseString(primary.stayCity) || parseString(raw.stayCity)
  return {
    ...raw,
    ...primary.basicInfo,
    name: primary.name,
    description: primary.description,
    stayCity: localizedStay,
  }
}

export function groupProcedureTranslationsByProcedureId(
  rows: Array<ProcedureTrRowLike & { procedureId: string }>
): Map<string, ProcedureTrRowLike[]> {
  const map = new Map<string, ProcedureTrRowLike[]>()
  for (const r of rows) {
    const list = map.get(r.procedureId) ?? []
    list.push(r)
    map.set(r.procedureId, list)
  }
  return map
}
