/**
 * Homepage data layer.
 *
 * `getHomepageData()` is the single entry point used by the homepage
 * server component. It tries to pull every section's content from
 * Strapi and merges it on top of the bundled `homepageDefaults`.
 *
 * The merge is per-section: if a Strapi fetch fails or returns empty,
 * the corresponding default content is kept, so the page always has
 * complete data.
 */

import { fetchSingle, getMediaUrl } from "@/lib/strapi/client"
import { isStrapiEnabled } from "@/lib/strapi/config"
import { titleCase } from "@/lib/api/casing"
import { normalizeCmsLink } from "@/lib/api/links"
import type {
  HomepageData,
  HeroSlideData,
  LeaderData,
  BusinessData,
  PartnerData,
  TestimonialData,
  InitiativeData,
  AwardData,
  PressReleaseData,
  PhilanthropicActivityData,
  VisionStatData,
  GlanceStatData,
  SectionHeader,
  StrapiMedia,
} from "@/lib/strapi/types"
import { homepageDefaults } from "./defaults"

/* ------------------------------------------------------------------ */
/*  Defensive field helpers                                           */
/* ------------------------------------------------------------------ */

type AnyRec = Record<string, unknown>

/** Read a property from a Strapi entry, handling both v4 (attributes) and v5 (flat). */
function attr(entry: unknown): AnyRec {
  if (!entry || typeof entry !== "object") return {}
  const e = entry as AnyRec
  if (e.attributes && typeof e.attributes === "object") {
    return e.attributes as AnyRec
  }
  return e
}

function str(val: unknown, fallback = ""): string {
  if (typeof val === "string") return val.trim() !== "" ? val : fallback
  if (typeof val === "number") return String(val)
  return fallback
}

function media(val: unknown): string {
  return getMediaUrl(val as StrapiMedia | null | undefined)
}

/** Coerce an unknown value into a record array (empty when not an array). */
function asArr(v: unknown): AnyRec[] {
  return Array.isArray(v) ? (v as AnyRec[]) : []
}

/** Read a section header (badge + description + icon) from a Strapi entry. */
function readHeader(a: AnyRec, fallback: SectionHeader): SectionHeader {
  return {
    badge: str(a.badge, fallback.badge),
    badgeIcon: fallback.badgeIcon,
    description: str(a.description, fallback.description) || fallback.description,
  }
}

/** Read a newline-separated text field into a string[] (backward-compatible with JSON arrays). */
function readLines(val: unknown, fallback: string[] | undefined): string[] {
  if (Array.isArray(val)) return val.filter((v) => typeof v === "string")
  if (typeof val === "string" && val.trim()) {
    try {
      const parsed = JSON.parse(val)
      if (Array.isArray(parsed)) return parsed.filter((v) => typeof v === "string")
    } catch {
      /* not JSON — treat as newline-separated text */
    }
    return val
      .split("\n")
      .map((l) => l.trim())
      .filter(Boolean)
  }
  return fallback ?? []
}

/* ------------------------------------------------------------------ */
/*  Per-section mappers                                               */
/* ------------------------------------------------------------------ */

function mapHeroSlides(rows: AnyRec[]): HeroSlideData[] {
  return rows.map((row, i) => {
    const a = attr(row)
    return {
      id: typeof a.id === "number" ? a.id : i,
      heading: str(a.heading),
      description: str(a.description),
      highlight: str(a.highlight),
      backgroundImage: media(a.backgroundImage_16x9) || str(a.backgroundImageUrl),
      mobileBackgroundImage: media(a.mobileBackgroundImage_9x16) || str(a.mobileBackgroundImageUrl),
      thumbnail: media(a.thumbnail_10x7) || media(a.backgroundImage_16x9) || str(a.thumbnailUrl),
      thumbnailAlt: str(a.thumbnailAlt, str(a.heading)),
    }
  })
}

function mapLeaders(rows: AnyRec[]): LeaderData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      name: str(a.name),
      title: str(a.title),
      image: media(a.image_6x5) || str(a.imageUrl),
    }
  })
}

function mapBusinesses(rows: AnyRec[]): BusinessData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      name: str(a.name),
      description: str(a.description),
      image: media(a.image_3x2) || str(a.imageUrl),
      logo: media(a.logo_1x1) || str(a.logoUrl),
      logoBg: str(a.logoBg, "#ffffff"),
    }
  })
}

function mapPartners(rows: AnyRec[]): PartnerData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      name: str(a.name),
      logo: media(a.logo_12x5) || str(a.logoUrl),
    }
  })
}

function mapTestimonials(rows: AnyRec[]): TestimonialData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      quote: str(a.quote),
      name: str(a.name),
      role: str(a.role),
      avatar: media(a.avatar_1x1) || str(a.avatarUrl),
      rating: typeof a.rating === "number" ? a.rating : Number(str(a.rating)) || 0,
    }
  })
}

function mapInitiatives(rows: AnyRec[]): InitiativeData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      number: str(a.number),
      title: str(a.title),
      description: str(a.description),
      image: media(a.image_9x4) || str(a.imageUrl),
    }
  })
}

function mapAwards(rows: AnyRec[]): AwardData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      year: str(a.year),
      title: str(a.title),
      image: media(a.image_1x1) || str(a.imageUrl),
    }
  })
}

function mapPressReleases(rows: AnyRec[], fallback: PressReleaseData[]): PressReleaseData[] {
  return rows.map((row, i) => {
    const a = attr(row)
    const fb = fallback[i]
    return {
      id: typeof a.id === "number" ? a.id : i + 1,
      image: media(a.image_16x9) || str(a.imageUrl) || fb?.image || "",
      date: str(a.date, fb?.date || ""),
      title: str(a.title, fb?.title || ""),
      description: str(a.description, fb?.description || ""),
      buttonText: str(a.buttonText, fb?.buttonText || "Read more"),
      buttonPdf: media(a.buttonPdf) || fb?.buttonPdf || "",
      buttonLink: normalizeCmsLink(a.buttonLink, fb?.buttonLink || ""),
    }
  })
}

function mapPhilanthropic(rows: AnyRec[]): PhilanthropicActivityData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      title: str(a.title),
      highlight: str(a.highlight),
      description: str(a.description),
      image: media(a.image_5x3) || str(a.imageUrl),
    }
  })
}

function mapVisionStats(rows: AnyRec[]): VisionStatData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      icon: media(a.icon_1x1) || str(a.iconUrl),
      value: str(a.value),
      label: str(a.label),
    }
  })
}

function mapGlanceStats(rows: AnyRec[]): GlanceStatData[] {
  return rows.map((row) => {
    const a = attr(row)
    return {
      icon: media(a.icon_1x1) || str(a.iconUrl),
      value: str(a.value),
      label: str(a.label),
    }
  })
}

/* ------------------------------------------------------------------ */
/*  Merge helpers                                                     */
/* ------------------------------------------------------------------ */

function withFallback<T>(value: T[] | undefined | null, fallback: T[]): T[] {
  return value && value.length > 0 ? value : fallback
}

const EMPTY_HEADER: SectionHeader = {}

/* ------------------------------------------------------------------ */
/*  Public API                                                        */
/* ------------------------------------------------------------------ */

/**
 * Fetch and assemble all homepage content.
 *
 * The homepage is a single Strapi document (`api::homepage.homepage`)
 * whose every section is a nested component. We fetch it once (the
 * controller deep-populates media + nested components) and map each
 * section onto `HomepageData`, falling back to the bundled defaults
 * field-by-field. When Strapi is not configured this resolves
 * synchronously to the defaults.
 */
export async function getHomepageData(): Promise<HomepageData> {
  const d = homepageDefaults

  if (!isStrapiEnabled) return d

  const entry = await fetchSingle<AnyRec>("homepage")

  if (!entry) return d

  /* Nested section components (flat objects in Strapi v5). */
  const hero = (entry.hero as AnyRec | undefined) ?? {}
  const leadership = (entry.leadership as AnyRec | undefined) ?? {}
  const vision = (entry.vision as AnyRec | undefined) ?? {}
  const legacy = (entry.legacy as AnyRec | undefined) ?? {}
  const businessPortfolio = (entry.businessPortfolio as AnyRec | undefined) ?? {}
  const partners = (entry.partners as AnyRec | undefined) ?? {}
  const glance = (entry.glance as AnyRec | undefined) ?? {}
  const testimonials = (entry.testimonials as AnyRec | undefined) ?? {}
  const sustainability = (entry.sustainability as AnyRec | undefined) ?? {}
  const awards = (entry.awards as AnyRec | undefined) ?? {}
  const eventEnquiry = (entry.eventEnquiry as AnyRec | undefined) ?? {}
  const pressRelease = (entry.pressRelease as AnyRec | undefined) ?? {}
  const philanthropic = (entry.philanthropic as AnyRec | undefined) ?? {}
  const gallery = (entry.gallery as AnyRec | undefined) ?? {}
  const newsletters = (entry.newsletters as AnyRec | undefined) ?? {}
  const partnerCta = (entry.partnerCta as AnyRec | undefined) ?? {}

  return {
    hero: {
      slides: mapHeroSlides(asArr(hero.slides)),
      ctaLabel: str(hero.ctaButtonText, homepageDefaults.hero.ctaLabel),
      ctaHref: normalizeCmsLink(hero.ctaButtonLink, homepageDefaults.hero.ctaHref),
    },
    leadership: {
      header: readHeader(leadership, EMPTY_HEADER),
      watermarkLines: readLines(leadership.watermarkLines, []),
      leaders: mapLeaders(asArr(leadership.leaders)),
    },
    vision: {
      header: readHeader(vision, EMPTY_HEADER),
      description: str(vision.description),
      image: media(vision.image_8x3) || homepageDefaults.vision.image,
      mobileImage: media(vision.mobileImage_1x1) || homepageDefaults.vision.mobileImage,
      stats: mapVisionStats(asArr(vision.stats)),
    },
    legacy: {
      header: readHeader(legacy, EMPTY_HEADER),
      backgroundImage: media(legacy.backgroundImage_3x2) || homepageDefaults.legacy.backgroundImage,
      image: media(legacy.image_16x9) || homepageDefaults.legacy.image,
      description: str(legacy.description, homepageDefaults.legacy.description),
      ctaLabel: str(legacy.ctaButtonText, homepageDefaults.legacy.ctaLabel),
      ctaHref: normalizeCmsLink(legacy.ctaButtonLink, homepageDefaults.legacy.ctaHref),
    },
    businessPortfolio: {
      header: readHeader(businessPortfolio, EMPTY_HEADER),
      businesses: mapBusinesses(asArr(businessPortfolio.businesses)),
    },
    partners: {
      header: readHeader(partners, EMPTY_HEADER),
      partners: mapPartners(asArr(partners.partners)),
    },
    glance: {
      header: readHeader(glance, EMPTY_HEADER),
      stats: mapGlanceStats(asArr(glance.stats)),
    },
    testimonials: {
      header: readHeader(testimonials, EMPTY_HEADER),
      mobileDescription: str(testimonials.mobileDescription),
      testimonials: mapTestimonials(asArr(testimonials.testimonials)),
    },
    sustainability: {
      header: readHeader(sustainability, EMPTY_HEADER),
      initiatives: mapInitiatives(asArr(sustainability.initiatives)),
    },
    awards: {
      header: readHeader(awards, EMPTY_HEADER),
      watermarkLines: readLines(awards.watermarkLines, []).map(titleCase),
      awards: mapAwards(asArr(awards.awards)),
    },
    eventEnquiry: {
      heading: str(eventEnquiry.heading, homepageDefaults.eventEnquiry.heading),
      ctaLabel: str(eventEnquiry.ctaButtonText, homepageDefaults.eventEnquiry.ctaLabel),
      ctaHref: normalizeCmsLink(eventEnquiry.ctaButtonLink, homepageDefaults.eventEnquiry.ctaHref),
    },
    pressRelease: {
      header: readHeader(pressRelease, EMPTY_HEADER),
      pressReleases: withFallback(
        mapPressReleases(
          asArr(pressRelease.pressReleases),
          homepageDefaults.pressRelease.pressReleases,
        ).filter((item) => item.image),
        homepageDefaults.pressRelease.pressReleases,
      ),
    },
    philanthropic: {
      header: readHeader(philanthropic, EMPTY_HEADER),
      watermarkText: titleCase(str(philanthropic.watermarkText)),
      activities: mapPhilanthropic(asArr(philanthropic.activities)),
    },
    galleryNewsletter: {
      galleryHeader: readHeader(gallery, EMPTY_HEADER),
      galleryImages: withFallback(
        asArr(gallery.images_3x2).map((row) => {
          const m = row as AnyRec
          return { url: media(m), alt: str(m.alternativeText) }
        }).filter((item) => item.url),
        homepageDefaults.galleryNewsletter.galleryImages,
      ),
      newsletterHeader: readHeader(newsletters, EMPTY_HEADER),
      newsletters: withFallback(asArr(newsletters.newsletters).map((row, i) => {
        const a = attr(row)
        const fb = homepageDefaults.galleryNewsletter.newsletters[i]
        return {
          title: str(a.title, fb?.title || ""),
          date: str(a.date, fb?.date || ""),
          image: media(a.image_1x1) || fb?.image || "",
          pdfUrl: media(a.pdfFile) || fb?.pdfUrl || "",
        }
      }).filter((item) => item.image), homepageDefaults.galleryNewsletter.newsletters),
    },
    partnerCta: {
      heading: str(partnerCta.heading, homepageDefaults.partnerCta.heading),
      headingLine2: str(partnerCta.headingLine2, homepageDefaults.partnerCta.headingLine2),
      ctaLabel: str(partnerCta.ctaButtonText, homepageDefaults.partnerCta.ctaLabel),
      ctaHref: normalizeCmsLink(partnerCta.ctaButtonLink, homepageDefaults.partnerCta.ctaHref),
    },
  }
}
