import type { PayloadHandler } from 'payload'
import type { Page } from '@/payload-types'

type IncludeKey = 'media' | 'forms' | 'globals' | 'snippets'
type SimpleSnippets = {
  bodyBottom?: string
  bodyTop?: string
  head?: string
}

const DEFAULT_MEDIA_SIZES = ['small', 'medium', 'large', 'og']
const ALLOWED_MEDIA_SIZES = new Set(DEFAULT_MEDIA_SIZES)

const GCS_BASE_URL = `${process.env.NEXT_PUBLIC_GOOGLE_STORAGE_URL}/${process.env.GCS_BUCKET}`

const parseCSV = (value: unknown): string[] =>
  String(value ?? '')
    .split(',')
    .map((s) => s.trim())
    .filter(Boolean)

const toBool = (value: unknown): boolean => Boolean(value)

const hasRealAssetRef = (value: unknown): value is string => {
  if (typeof value !== 'string') return false
  const trimmed = value.trim()
  if (!trimmed) return false

  const cleanPath = trimmed.split('?')[0]?.split('#')[0] ?? trimmed
  const lastSegment = cleanPath.split('/').pop()?.trim().toLowerCase()

  return Boolean(lastSegment && lastSegment !== 'null')
}

const asId = (value: any): number | null => {
  if (value == null) return null
  if (typeof value === 'number') return Number.isFinite(value) ? value : null
  if (typeof value === 'string') return /^\d+$/.test(value) ? Number(value) : null
  if (typeof value === 'object' && value.id != null) return asId(value.id)
  return null
}

const toAbsoluteGCSUrl = (url?: string | null) => {
  if (!hasRealAssetRef(url)) return null
  if (url.startsWith('http://') || url.startsWith('https://')) return url
  const filename = url.split('/').pop()
  if (!filename) return null
  return `${GCS_BASE_URL}/${filename}`
}

const pickMedia = (m: any, sizesWanted: string[] | null) => {
  if (!m) return null

  const out: any = {
    id: m.id,
    url: toAbsoluteGCSUrl(m.url),
    thumbnailURL: toAbsoluteGCSUrl(m.thumbnailURL),
    filename: m.filename,
    mimeType: m.mimeType,
    filesize: m.filesize,
    width: m.width,
    height: m.height,
    alt: m.alt ?? null,
    caption: m.caption ?? null,
    focalX: m.focalX ?? null,
    focalY: m.focalY ?? null,
  }

  if (m.sizes && sizesWanted?.length) {
    const sizes: Record<string, any> = {}
    for (const k of sizesWanted) {
      const s = m.sizes?.[k]
      const sizeUrl = toAbsoluteGCSUrl(s?.url)
      if (sizeUrl) {
        sizes[k] = {
          url: sizeUrl,
          width: s.width,
          height: s.height,
          mimeType: s.mimeType,
          filesize: s.filesize,
          filename: s.filename,
        }
      }
    }
    if (Object.keys(sizes).length) out.sizes = sizes
  }

  return out
}

const pickForm = (f: any) => ({
  id: f.id,
  title: f.title ?? null,
  description: f.description ?? null,
  fields: f.fields ?? [],
  submitButtonLabel: f.submitButtonLabel ?? null,
  submitButtonId: f.submitButtonId ?? null,
  confirmationType: f.confirmationType ?? null,
  confirmationMessage: f.confirmationMessage ?? null,
  successMessage: f.successMessage ?? null,
  redirect: (() => {
    if (!f.redirect) return null

    const redirect = {
      ...f.redirect,
      openInNewTab: Boolean(f.redirect?.openInNewTab),
    }

    if (redirect?.redirectType === 'external') {
      const { slug, head, bodyTop, bodyBottom, ...rest } = redirect
      return rest
    }

    return redirect
  })(),
})

const compactDeep = (value: any): any => {
  if (value === null || value === undefined) return undefined
  if (Array.isArray(value)) {
    const arr = value.map(compactDeep).filter((v) => v !== undefined)
    return arr.length ? arr : undefined
  }
  if (typeof value === 'object') {
    const out: any = {}
    for (const [k, v] of Object.entries(value)) {
      const c = compactDeep(v)
      if (c !== undefined) out[k] = c
    }
    return Object.keys(out).length ? out : undefined
  }
  return value
}

const cleanSnippetValue = (value: unknown): string | undefined => {
  if (typeof value !== 'string') return undefined
  const normalized = value.trim()
  return normalized ? normalized : undefined
}

const pickSnippets = (snippets: unknown): SimpleSnippets | undefined => {
  if (!snippets || typeof snippets !== 'object') return undefined

  const source = snippets as Record<string, unknown>
  const out: SimpleSnippets = {
    head: cleanSnippetValue(source.head),
    bodyTop: cleanSnippetValue(source.bodyTop),
    bodyBottom: cleanSnippetValue(source.bodyBottom),
  }

  if (!out.head && !out.bodyTop && !out.bodyBottom) return undefined
  return out
}

const joinSnippetParts = (...parts: Array<string | undefined>): string | undefined => {
  const merged = parts.filter(Boolean).join('\n')
  return merged || undefined
}

const mergeSnippets = (
  globalSnippets?: SimpleSnippets,
  pageSnippets?: SimpleSnippets,
): SimpleSnippets | undefined => {
  const merged: SimpleSnippets = {
    head: joinSnippetParts(globalSnippets?.head, pageSnippets?.head),
    bodyTop: joinSnippetParts(globalSnippets?.bodyTop, pageSnippets?.bodyTop),
    bodyBottom: joinSnippetParts(globalSnippets?.bodyBottom, pageSnippets?.bodyBottom),
  }

  if (!merged.head && !merged.bodyTop && !merged.bodyBottom) return undefined
  return merged
}

function normalizeLayout(
  layout: any[],
  mediaIDs: Set<number>,
  formIDs: Set<number>,
  opts: { includeMeta: boolean },
) {
  if (!Array.isArray(layout)) return []

  return layout.map((block) => {
    const type = block.blockType
    const id = block.id

    const props: any = { ...block }
    delete props.blockType
    delete props.blockName
    delete props.id

    if (!opts.includeMeta) {
      delete props.meta
    } else {
      // General optimization for meta.backgroundImage available on all blocks
      const metaBgId = asId(props.meta?.backgroundImage)
      if (metaBgId) {
        mediaIDs.add(metaBgId)
        props.meta.backgroundImageId = metaBgId
        delete props.meta.backgroundImage
      }
    }

    if (type === 'heroOfferV1') {
      const desktopId = asId(props.desktopImage)
      if (desktopId) mediaIDs.add(desktopId)
      props.desktopImageId = desktopId
      delete props.desktopImage

      const mobileId = asId(props.mobileImage)
      if (mobileId) mediaIDs.add(mobileId)
      props.mobileImageId = mobileId
      delete props.mobileImage

      if (Array.isArray(props.highlights)) {
        props.highlights = props.highlights.map((h: any) => {
          const iconId = asId(h.icon)
          if (iconId) mediaIDs.add(iconId)
          return { label: h.label, iconId }
        })
      }
    }

    if (type === 'contentListV1') {
      const ornamentId = asId(props.ornament)
      if (ornamentId) mediaIDs.add(ornamentId)
      props.ornamentId = ornamentId
      delete props.ornament

      if (Array.isArray(props.items)) {
        props.items = props.items.map((it: any) => {
          const imageId = asId(it.image)
          if (imageId) mediaIDs.add(imageId)

          const iconId = asId(it.icon)
          if (iconId) mediaIDs.add(iconId)

          const { image, icon, ...rest } = it
          return { ...rest, imageId, iconId }
        })
      }
    }

    if (type === 'imageGalleryStripV1') {
      if (Array.isArray(props.images)) {
        props.images = props.images.map((img: any) => {
          const imageId = asId(img.image)
          if (imageId) mediaIDs.add(imageId)
          return { alt: img.alt ?? null, imageId }
        })
      }
    }

    if (type === 'testimonial') {
      if (Array.isArray(props.ratings)) {
        props.ratings = props.ratings.map((r: any) => {
          const iconId = asId(r['platform-icon'])
          if (iconId) mediaIDs.add(iconId)
          const { 'platform-icon': _, ...rest } = r
          return { ...rest, platformIconId: iconId }
        })
      }

      if (Array.isArray(props.items)) {
        props.items = props.items.map((it: any) => {
          const avatarId = asId(it.avatar)
          if (avatarId) mediaIDs.add(avatarId)
          const { avatar, ...rest } = it
          return { ...rest, avatarId }
        })
      }
    }

    if (type === 'leadFormV1' || type === 'formBlock') {
      const formId = asId(props.form)
      if (formId) formIDs.add(formId)
      props.formId = formId
      delete props.form
      props.enableIntro = toBool(props.enableIntro)
    }

    return { id, type, props }
  })
}

export const renderPageBySlug: PayloadHandler = async (req) => {
  const { slug } = req.routeParams as { slug: string }

  const include = new Set(parseCSV((req.query as any)?.include) as IncludeKey[])
  const includeMeta = String((req.query as any)?.includeMeta ?? 'true') !== 'false'
  const compact = String((req.query as any)?.compact ?? 'false') === 'true'
  const draft = String((req.query as any)?.draft || '') === 'true'
  const snippetsMode = String((req.query as any)?.snippetsMode ?? 'resolved')

  const mediaSizesRaw = (req.query as any)?.mediaSizes
  const mediaSizesParam = parseCSV(mediaSizesRaw).filter((size) => ALLOWED_MEDIA_SIZES.has(size))
  const hasMediaSizesParam =
    mediaSizesRaw !== undefined && mediaSizesRaw !== null && String(mediaSizesRaw).trim() !== ''
  const sizesWanted = include.has('media')
    ? hasMediaSizesParam
      ? mediaSizesParam
      : DEFAULT_MEDIA_SIZES
    : null

  const found = await req.payload.find({
    collection: 'pages',
    where: { slug: { equals: slug } },
    depth: 0,
    draft,
    limit: 1,
    overrideAccess: false,
  })

  const page = found.docs?.[0] as Page | undefined
  if (!page) return Response.json({ error: 'NOT_FOUND' }, { status: 404 })
  if (!draft && page._status !== 'published') {
    return Response.json({ error: 'NOT_FOUND' }, { status: 404 })
  }

  const mediaIDs = new Set<number>()
  const formIDs = new Set<number>()

  // Capture meta image ID
  const pageMetaImageId = asId(page.meta?.image)
  if (pageMetaImageId) mediaIDs.add(pageMetaImageId)

  const layout = normalizeLayout((page as any).layout, mediaIDs, formIDs, { includeMeta })

  let snippets:
    | SimpleSnippets
    | {
        global?: SimpleSnippets
        page?: SimpleSnippets
        resolved?: SimpleSnippets
      }
    | undefined

  if (include.has('snippets')) {
    const scriptsGlobal = await req.payload.findGlobal({
      slug: 'scripts',
      depth: 0,
    })

    const globalSnippets = pickSnippets((scriptsGlobal as any)?.snippets)
    const pageSnippets = pickSnippets((page as any)?.meta?.snippets)
    const resolvedSnippets = mergeSnippets(globalSnippets, pageSnippets)

    if (globalSnippets || pageSnippets || resolvedSnippets) {
      snippets =
        snippetsMode === 'full'
          ? {
              global: globalSnippets,
              page: pageSnippets,
              resolved: resolvedSnippets,
            }
          : resolvedSnippets
    }
  }

  let includedGlobals: Record<string, any> | undefined
  let header: any
  let footer: any

  if (include.has('globals')) {
    // Resolve Header
    const headerVariant = page.layoutSettings?.headerVariant ?? 'inherit'
    if (headerVariant === 'shared' && page.layoutSettings?.headerOverride) {
      const shared = await req.payload.findByID({
        collection: 'shared-layouts',
        id: asId(page.layoutSettings.headerOverride)!,
        depth: 0,
      })
      header = (shared as any)?.headerConfig
    } else {
      header = await req.payload.findGlobal({ slug: 'header', depth: 0 })
      if (headerVariant === 'landing') header.variant = 'landing'
      else if (headerVariant === 'default') header.variant = 'default'
    }

    // Resolve Footer
    const footerVariant = page.layoutSettings?.footerVariant ?? 'inherit'
    if (footerVariant === 'shared' && page.layoutSettings?.footerOverride) {
      const shared = await req.payload.findByID({
        collection: 'shared-layouts',
        id: asId(page.layoutSettings.footerOverride)!,
        depth: 0,
      })
      footer = (shared as any)?.footerConfig
    } else {
      footer = await req.payload.findGlobal({ slug: 'footer', depth: 0 })
      if (footerVariant === 'landing') footer.variant = 'landing'
      else if (footerVariant === 'default') footer.variant = 'default'
    }

    includedGlobals = { header, footer }

    if (include.has('media')) {
      const headerLogoId = asId(header?.logo)
      if (headerLogoId) mediaIDs.add(headerLogoId)
    }

    if (include.has('forms')) {
      const footerFormId = asId(footer?.newsletter?.form)
      if (footerFormId) formIDs.add(footerFormId)
    }
  }

  let includedMedia: Record<string, any> | undefined
  if (include.has('media') && mediaIDs.size) {
    const ids = Array.from(mediaIDs)
    const mediaRes = await req.payload.find({
      collection: 'media',
      where: { id: { in: ids } },
      depth: 1,
      limit: ids.length,
    })

    includedMedia = {}
    for (const m of mediaRes.docs as any[]) {
      const picked = pickMedia(m, sizesWanted)
      if (picked) includedMedia[String(m.id)] = picked
    }
  }

  let includedForms: Record<string, any> | undefined
  if (include.has('forms') && formIDs.size) {
    const ids = Array.from(formIDs)
    const formsRes = await req.payload.find({
      collection: 'forms',
      where: { id: { in: ids } },
      depth: 1,
      limit: ids.length,
    })

    includedForms = {}
    for (const f of formsRes.docs as any[]) {
      includedForms[String(f.id)] = pickForm(f)
    }
  }

  const layoutSettings = { ...(page as any).layoutSettings } || {
    headerVariant: 'inherit',
    footerVariant: 'inherit',
  }

  // Resolve Floating CTA if present
  if (layoutSettings.floatingCTA) {
    try {
      const ctaId = asId(layoutSettings.floatingCTA)
      if (ctaId) {
        const cta = await req.payload.findByID({
          collection: 'shared-ctas',
          id: ctaId,
          depth: 0,
        })
        if (cta) {
          layoutSettings.floatingCTA = {
            id: cta.id,
            label: (cta as any).label,
            href: (cta as any).href,
            style: (cta as any).style,
            ctaId: (cta as any).ctaId ?? null,
          }
        }
      }
    } catch (e) {
      // Silent fail for floating cta resolution
    }
  }

  let body: any = {
    page: {
      id: page.id,
      title: page.title,
      slug: (page as any).slug,
      meta: (page as any).meta
        ? {
            ...((page as any).meta ?? {}),
            metaImageId: pageMetaImageId,
          }
        : null,
      publishedAt: (page as any).publishedAt ?? null,
      updatedAt: (page as any).updatedAt ?? null,
    },
    layoutSettings,
    layout,
  }

  if (snippets) body.snippets = snippets

  const included: any = {}
  if (includedMedia) included.media = includedMedia
  if (includedForms) included.forms = includedForms
  if (includedGlobals) included.globals = includedGlobals
  if (Object.keys(included).length) body.included = included

  if (compact) body = compactDeep(body) ?? {}

  const headers = new Headers({ 'content-type': 'application/json' })
  if (!draft) {
    headers.set('cache-control', 'public, max-age=60, s-maxage=300, stale-while-revalidate=600')
  }

  return new Response(JSON.stringify(body), { status: 200, headers })
}

