import Link from "next/link";
import type { ReactNode } from "react";
import { AboutSection } from "@/components/home/AboutSection";
import { EventCard } from "@/components/events/event-card";
import { EventStackSection, type EventCardData } from "@/components/home/EventStackSection";
import { HeroBanner } from "@/components/home/HeroBanner";
import { getEvents, getSignatureEvent } from "@/lib/api/events";
import { getPublicAnnouncements, getPublicBanners, getPublicHomepageSections } from "@/lib/api/cms";
import { EVENT_STATUS_LABEL } from "@/lib/labels";
import { buttonClasses } from "@/components/ui/button";
import { FOCUS_RING_CLASSES, FOCUS_RING_TIGHT_CLASSES } from "@/components/ui/styles";
import { cn } from "@/lib/utils";
import { formatCurrency, formatDate } from "@/lib/format";
import type { KolaboraEvent } from "@/types/event";
import { QueueSection } from "@/components/motion/QueueSection";
import { QueueItem } from "@/components/motion/QueueItem";
import { RevealText } from "@/components/motion/RevealText";
import { StaggerGrid } from "@/components/motion/StaggerGrid";

function toStackCardData(event: KolaboraEvent): EventCardData {
  const prices = (event.ticket_types ?? [])
    .flatMap((t) => t.phases ?? [])
    .map((phase) => Number(phase.price))
    .filter((price) => !Number.isNaN(price));
  const minPrice = prices.length > 0 ? Math.min(...prices) : null;

  return {
    slug: event.slug,
    title: event.title,
    category: event.category?.name ?? "Event",
    date: formatDate(event.start_date),
    location: event.location ?? "",
    price: minPrice !== null ? `From ${formatCurrency(minPrice)}` : null,
    thumbnail: event.thumbnail ?? undefined,
    statusLabel: EVENT_STATUS_LABEL[event.status] ?? event.status,
  };
}

export default async function HomePage() {
  const [eventsRes, featuredRes, signatureRes, announcementsRes, bannersRes, sectionsRes] =
    await Promise.all([
      getEvents({ sort: "upcoming" }),
      getEvents({ sort: "popular" }),
      getSignatureEvent(),
      getPublicAnnouncements(),
      getPublicBanners(),
      getPublicHomepageSections(),
    ]);

  const signatureEvent = signatureRes.data;
  // Unlike featuredEvents below, the signature event is NOT excluded here —
  // /events (the full listing) already shows it too, and excluding it from
  // this grid meant the "Event Berlangsung" section stayed empty whenever
  // the signature event was the only one live.
  const events = eventsRes.data.slice(0, 6);
  // FR-010 Featured Event: ranked by tickets actually sold, distinct from
  // FR-013 Upcoming Event (chronological) above — only shown once at least
  // one event has real sales, otherwise "featured" would be meaningless.
  const featuredEvents = featuredRes.data
    .filter((event) => event.id !== signatureEvent?.id && (event.tickets_sold ?? 0) > 0)
    .slice(0, 3);
  const announcements = announcementsRes.data;
  const banners = bannersRes.data;
  // FR-CMS-007/014: visible sections only, already sorted by display_order.
  const sections = sectionsRes.data;

  const sectionContent: Record<string, ReactNode> = {
    announcement_bar: announcements.length > 0 && (
      <div className="flex flex-col gap-1 bg-kolabora-tertiary/10 px-6 py-2 text-center text-sm">
        {announcements.map((announcement) => (
          <p key={announcement.id}>
            <span className="font-medium">{announcement.title}:</span> {announcement.content}
          </p>
        ))}
      </div>
    ),

    // Sticky-scroll reveal: Hero stays pinned to the top of the viewport for
    // the ENTIRE time it takes About to rise up and fully cover it, so Hero
    // itself never visibly moves — only About slides. Math: Hero sticks for
    // exactly (wrapperHeight - heroHeight) of scroll. Hero's own height is
    // ~90vh, and About needs one full viewport (~100vh) of scroll to rise
    // from below the fold to fully covering it — so the wrapper needs
    // ~90vh + 100vh = 190vh, and About's negative margin needs to equal
    // Hero's height (~90vh) so that "fully covered" lines up with the exact
    // moment Hero's pin naturally ends (only after that does Hero resume
    // scrolling — invisibly, since About already fully hides it by then).
    // `isolate` keeps Hero's internal z-index layers (grain overlay etc.)
    // from leaking out and painting above About. About is a full min-h-screen
    // panel (not just its short content's natural height) so it stays
    // covering the viewport for the whole transition; a shorter About would
    // itself finish scrolling past before Hero has fully scrolled away,
    // leaving Hero's tail-end peeking through the gap.
    hero: (
      <div className="relative min-h-[190vh]">
        <div className="sticky top-0 isolate">
          <HeroBanner
            signatureEvent={signatureEvent ? { title: signatureEvent.title, slug: signatureEvent.slug } : undefined}
          />
        </div>
      </div>
    ),

    about: <AboutSection />,

    search: (
      <section className="mx-auto max-w-6xl px-6 py-6">
        <form action="/events" method="get" className="mx-auto flex max-w-xl gap-2">
          {/* Pill-shaped search input is a deliberate one-off (Homepage's primary
              affordance) — kept as a plain input rather than forcing it through
              the shared `rounded-lg` Input primitive, to avoid two conflicting
              border-radius utilities on one element. */}
          <input
            type="search"
            name="search"
            placeholder="Search events, e.g. concerts, workshops..."
            className={cn(
              "flex-1 rounded-full border border-kolabora-neutral-dark/20 px-4 py-2.5 text-sm",
              FOCUS_RING_TIGHT_CLASSES,
            )}
          />
          <button type="submit" className={buttonClasses("primary", "md")}>
            Search
          </button>
        </form>
      </section>
    ),

    banner_promo: banners.length > 0 && (
      <section className="mx-auto max-w-6xl px-6 pt-10">
        <StaggerGrid className="flex gap-4 overflow-x-auto" stagger={0.08} distance={16} duration={0.4}>
          {banners.map((banner) =>
            banner.link_url ? (
              <a key={banner.id} href={banner.link_url} className="shrink-0">
                {/* eslint-disable-next-line @next/next/no-img-element -- admin-provided URL, not on next/image allowlist */}
                <img
                  src={banner.image_url}
                  alt={banner.title ?? "Banner"}
                  className="h-32 w-64 rounded-xl object-cover"
                />
              </a>
            ) : (
              // eslint-disable-next-line @next/next/no-img-element -- admin-provided URL, not on next/image allowlist
              <img
                key={banner.id}
                src={banner.image_url}
                alt={banner.title ?? "Banner"}
                className="h-32 w-64 shrink-0 rounded-xl object-cover"
              />
            ),
          )}
        </StaggerGrid>
      </section>
    ),

    // Consolidates what used to be 3 separate sections (categories,
    // featured_events, upcoming_events) into one "Event" section, per the
    // homepage redesign wireframe. Category filter chips were dropped —
    // with so few events live at once, a category filter here just adds
    // clutter; browsing by category still works from the full /events page.
    events: (
      <section className="mx-auto max-w-6xl px-6 py-10">
        <QueueSection as="div" amount={0.3}>
          <RevealText as="h2" text="Event" className="text-xl font-semibold" />

          {featuredEvents.length > 0 && (
            <QueueItem as="div" className="mt-10">
              <RevealText as="h3" text="Featured Events" className="text-lg font-medium" />
              <StaggerGrid className="mt-4 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
                {featuredEvents.map((event) => (
                  <EventCard key={event.id} event={event} />
                ))}
              </StaggerGrid>
            </QueueItem>
          )}

          <QueueItem as="div" className="mt-10">
            <div className="flex items-center justify-between">
              <RevealText as="h3" text="Ongoing Events" className="text-lg font-medium" />
              <Link
                href="/events"
                className={cn("rounded text-sm font-medium text-kolabora-primary", FOCUS_RING_CLASSES)}
              >
                View all
              </Link>
            </div>

            {events.length === 0 ? (
              <p className="mt-4 text-kolabora-neutral-dark/70">
                No events published yet.
              </p>
            ) : (
              <StaggerGrid className="mt-4 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
                {events.map((event) => (
                  <EventCard key={event.id} event={event} />
                ))}
              </StaggerGrid>
            )}
          </QueueItem>
        </QueueSection>
      </section>
    ),

  };

  return (
    <div>
      {sections.map((section) => (
        <div key={section.key}>
          {sectionContent[section.key] ?? null}
          {/* Not a CMS-managed section — mounted directly after "about"
              here rather than via the sections table/seeder. Wired to the
              same real published-events data as "Event Berlangsung" below
              (guarded on non-empty since the stack math divides by the
              card count); falls back to its own placeholder defaults only
              if rendered with no events prop at all.
              md:-mt-[100vh]/z-20 (desktop only, matching AboutSection's own
              md:min-h-[200vh] hand-off room): pulls this up to slide over
              About and cover it right as About's zoom-out finishes, instead
              of an abrupt cut — same negative-margin trick Hero/About
              itself uses one section up. */}
          {section.key === "about" && events.length > 0 && (
            // id read by HeroBanner's floating CTA (see its useEffect) to
            // know exactly when Event starts sliding over About, so the CTA
            // can disappear right at that boundary instead of lingering
            // into Event's own screen space.
            <div id="home-event-section" className="relative z-20 md:-mt-[100vh]">
              <EventStackSection events={events.slice(0, 4).map(toStackCardData)} />
            </div>
          )}
        </div>
      ))}
    </div>
  );
}
