import * as React from 'react';
import { Link } from 'react-router-dom';
import { ArrowRight, ArrowUpRight, GitBranch, Menu } from 'lucide-react';

import { listDemos } from '@/lib/demo-kit/registry';
import type { DemoMeta } from '@/lib/demo-kit/types';
import { lineup, routes } from '@/content/lineup';
import type { VerticalEntry } from '@/content/verticals';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
  navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu';
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/components/ui/accordion';
import {
  Sheet,
  SheetBody,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from '@/components/ui/sheet';
import { ContrastToggle } from '@/components/site/ContrastToggle';
import { DemoIcon } from '@/components/site/DemoIcon';
import { PIG_URL, REPO_URL, VERIFIERS_WORDLE_URL } from '@/components/site/links';
import { ThemeToggle } from '@/components/site/ThemeToggle';
import { Wordmark } from '@/components/site/Wordmark';
import { cn } from '@/lib/utils';

/*
 * This header is GENERATED. Nothing in it names a demo.
 *
 * Adding `src/demos/<slug>/` puts that demo in the Demos panel, in its
 * vertical, and (if it is the first live one) behind the CTA, with zero edits
 * to this file. The only hand-written lists here are the five concepts under
 * "How it works", which are properties of the idea rather than of the lineup.
 */

/**
 * The real upstream taskset, quoted rather than paraphrased.
 *
 * A mega-menu that contains source code instead of more links is the cheapest
 * signal on the whole site that this is not a brochure — it is the first thing
 * a technical buyer sees, and it is true before they have clicked anything.
 */
const TASKSET_SOURCE = `class WordleConfig(TextArenaConfig):
    game: Literal["Wordle-v0"] = "Wordle-v0"

class WordleTaskset(TextArenaTaskset, vf.Taskset[TextArenaTask, WordleConfig]):
    pass`;

const CONCEPTS: readonly { term: string; gloss: string }[] = [
  {
    term: 'Environment',
    gloss: 'The task, the legal moves and the grader, packaged so anyone can install and run it.',
  },
  {
    term: 'Rollout',
    gloss: 'One episode. The model acts, the environment answers, and every turn is recorded.',
  },
  {
    term: 'Reward',
    gloss: 'The number the run is scored on. You write it, so you decide what "good" means.',
  },
  {
    term: 'Harness',
    gloss: 'The runner that plays a taskset against a model and keeps the receipts.',
  },
  {
    term: 'Held-out grading',
    gloss: 'Scored on problems the model has never seen, which is the only way the score means anything.',
  },
];

/**
 * The header's Verticals panel shows the LINEUP, not the registry's groups.
 *
 * `listVerticals()` only ever contains verticals that already have a demo —
 * today that is one group, `reference`, which `src/content/verticals.ts` is
 * explicit is not an industry and must never be presented as one. The twelve
 * proposals each have a real page at `/verticals/<slug>`, so the panel links
 * there. `VerticalEntry.slug` is the route's slug; the registry's `Vertical`
 * key is a different, shorter string and is deliberately not used for URLs.
 */
type HeaderVertical = VerticalEntry;

function useLineup() {
  return React.useMemo(() => {
    // `listDemos` already returns a fresh array sorted by order then slug, and
    // `listVerticals` already drops the empty verticals. Neither needs redoing
    // here — if this file starts re-sorting the lineup, the header and the
    // gallery will eventually disagree about what "first" means.
    const demos = listDemos();
    const live = demos.filter((demo) => demo.status === 'live');
    const spec = demos.filter((demo) => demo.status === 'spec');

    // Already sorted by rank in `@/content/lineup`. Copied rather than passed
    // through, because the panel props are mutable arrays and `lineup` is the
    // one every page reads.
    const verticals: HeaderVertical[] = [...lineup];

    // The CTA follows the lineup rather than naming a slug. Today the first
    // live demo IS the word game, so this resolves to the wordle route; when a
    // second one ships ahead of it, the button moves with it and this file does
    // not change.
    const primary = live[0] ?? demos[0];
    const ctaHref = primary ? `/demos/${primary.slug}` : '/demos';

    return { live, spec, verticals, ctaHref };
  }, []);
}

/* ------------------------------------------------------------------ panels */

/**
 * Spreads `...rest` onto the Link, and that is not tidiness.
 *
 * Both `NavigationMenuLink asChild` and `SheetClose asChild` work by cloning
 * this element and merging their own `onClick` into it. A component that takes
 * `demo` and ignores everything else silently drops those handlers: the row
 * still navigates, and the mega panel or the mobile sheet stays open on top of
 * the page you just arrived at.
 */
function DemoRow({
  demo,
  muted = false,
  className,
  ...rest
}: { demo: DemoMeta; muted?: boolean } & Omit<React.ComponentProps<typeof Link>, 'to'>) {
  return (
    <Link
      to={`/demos/${demo.slug}`}
      className={cn(
        'flex gap-3 rounded-lg p-2.5 transition-colors duration-1 ease-enter hover:bg-surface-2',
        muted && 'opacity-70 hover:opacity-100',
        className,
      )}
      {...rest}
    >
      <DemoIcon name={demo.icon} className="mt-0.5 size-4 text-accent-fg" />
      <span className="flex min-w-0 flex-col gap-0.5">
        <span className="flex items-center gap-2 text-sm font-medium text-fg">
          {demo.title}
          {demo.status === 'spec' ? (
            <Badge variant="outline" className="font-normal">
              Spec
            </Badge>
          ) : null}
        </span>
        <span className="text-xs leading-relaxed text-muted">
          {/*
            A spec demo shows the BUYER, not the technology: "Head of Claims"
            says who is meant to care, where a taskset name says nothing to the
            person reading this in a boardroom.
          */}
          {demo.status === 'spec' ? `For the ${demo.persona}` : demo.tagline}
        </span>
      </span>
    </Link>
  );
}

function PanelHeading({ children }: { children: React.ReactNode }) {
  return (
    <p className="px-2.5 pb-1 text-xs font-semibold uppercase tracking-wider text-muted">
      {children}
    </p>
  );
}

function DemosPanel({ live, spec }: { live: DemoMeta[]; spec: DemoMeta[] }) {
  return (
    <div className="w-[min(92vw,720px)]">
      <div className="grid grid-cols-2 gap-4 p-4">
        <section aria-label="Live now" className="flex flex-col gap-0.5">
          <PanelHeading>Live now</PanelHeading>
          {live.length > 0 ? (
            live.map((demo) => (
              <NavigationMenuLink asChild key={demo.slug}>
                <DemoRow demo={demo} />
              </NavigationMenuLink>
            ))
          ) : (
            <p className="p-2.5 text-xs text-muted">No interactive demos published yet.</p>
          )}
        </section>

        <section
          aria-label="Shipping next"
          className="flex flex-col gap-0.5 border-l border-border pl-4"
        >
          <PanelHeading>Shipping next</PanelHeading>
          {spec.length > 0 ? (
            spec.map((demo) => (
              <NavigationMenuLink asChild key={demo.slug}>
                <DemoRow demo={demo} muted />
              </NavigationMenuLink>
            ))
          ) : (
            <p className="p-2.5 text-xs text-muted">Nothing queued.</p>
          )}
        </section>
      </div>

      <div className="flex items-center justify-between gap-4 border-t border-border bg-surface-2 px-5 py-3">
        <p className="text-xs text-muted">
          Every demo replays a real rollout from a real environment.
        </p>
        <NavigationMenuLink asChild>
          <Link
            to="/demos"
            className="inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent-fg underline-offset-4 hover:underline"
          >
            Browse all demos
            <ArrowRight aria-hidden="true" className="size-3.5" />
          </Link>
        </NavigationMenuLink>
      </div>
    </div>
  );
}

function VerticalsPanel({ verticals }: { verticals: HeaderVertical[] }) {
  return (
    <div className="w-[min(92vw,720px)] p-4">
      {verticals.length > 0 ? (
        <div className="grid grid-cols-2 gap-x-4 gap-y-0.5">
          {verticals.map((vertical) => (
            <NavigationMenuLink asChild key={vertical.slug}>
              <Link
                to={routes.vertical(vertical.slug)}
                className="flex gap-3 rounded-lg p-2.5 transition-colors duration-1 ease-enter hover:bg-surface-2"
              >
                <DemoIcon name={vertical.icon} className="mt-0.5 size-4 text-accent-fg" />
                <span className="flex min-w-0 flex-col gap-0.5">
                  <span className="text-sm font-medium text-fg">{vertical.title}</span>
                  {/* The budget holder, not the reward sentence: a nav row has
                      one line, and "who buys this" is the more useful half. */}
                  <span className="text-xs leading-relaxed text-muted">{vertical.persona}</span>
                </span>
              </Link>
            </NavigationMenuLink>
          ))}
        </div>
      ) : (
        <p className="p-2.5 text-xs text-muted">No verticals in the lineup yet.</p>
      )}
    </div>
  );
}

function TasksetSource({ className }: { className?: string }) {
  return (
    <div className={cn('flex flex-col gap-2 rounded-lg border border-border bg-bg p-3', className)}>
      <p className="text-xs font-semibold uppercase tracking-wider text-muted">
        The actual taskset
      </p>
      {/*
        Wrapped, not scrolled. The source is quoted verbatim — reformatting it
        to fit would make it stop being a quote — and the widest line is a third
        wider than this column at any font size worth reading. In a panel whose
        entire job is "this is real code", a visible wrap beats a third of the
        line hidden behind a scrollbar nobody in a boardroom will drag.
      */}
      <pre className="overflow-x-auto whitespace-pre-wrap break-words text-[11px] leading-relaxed text-fg">
        <code className="font-mono">{TASKSET_SOURCE}</code>
      </pre>
      <a
        href={VERIFIERS_WORDLE_URL}
        target="_blank"
        rel="noreferrer noopener"
        className="inline-flex items-center gap-1 text-xs font-medium text-accent-fg underline-offset-4 hover:underline"
      >
        verifiers/environments/wordle
        <ArrowUpRight aria-hidden="true" className="size-3.5" />
      </a>
    </div>
  );
}

function HowItWorksPanel({ ctaHref }: { ctaHref: string }) {
  return (
    <div
      // 820px, not more: the panel hangs off the LEFT edge of the nav, which
      // starts about 100px in, so anything wider pushes past the right edge of
      // a 1024px laptop and gives the whole page a horizontal scrollbar.
      className="w-[min(90vw,820px)] p-4"
    >
      <div className="grid grid-cols-[minmax(0,0.85fr)_minmax(0,1fr)] gap-4">
        <dl className="flex flex-col gap-3">
          {CONCEPTS.map((concept) => (
            <div key={concept.term} className="flex flex-col gap-0.5">
              <dt className="text-sm font-medium text-fg">{concept.term}</dt>
              <dd className="text-xs leading-relaxed text-muted">{concept.gloss}</dd>
            </div>
          ))}
          <NavigationMenuLink asChild>
            <Link
              to={ctaHref}
              className="mt-1 inline-flex items-center gap-1 text-xs font-medium text-accent-fg underline-offset-4 hover:underline"
            >
              See all five on one recorded run
              <ArrowRight aria-hidden="true" className="size-3.5" />
            </Link>
          </NavigationMenuLink>
        </dl>
        <TasksetSource />
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ mobile */

function MobileNav({
  live,
  spec,
  verticals,
  ctaHref,
}: {
  live: DemoMeta[];
  spec: DemoMeta[];
  verticals: HeaderVertical[];
  ctaHref: string;
}) {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="ghost" size="icon-touch" aria-label="Open menu">
          <Menu aria-hidden="true" />
        </Button>
      </SheetTrigger>
      {/*
        The sheet is a flex column: header, a scrolling body, then a pinned
        footer. Scrolling the BODY rather than the content root is what keeps a
        long lineup reachable on a short phone, and `overscroll-contain` on it
        stops the flick chaining into the page underneath.
      */}
      <SheetContent side="right" className="w-[min(92vw,24rem)]">
        <SheetHeader>
          <SheetTitle>Menu</SheetTitle>
          <SheetDescription className="sr-only">
            Demos, verticals, and how these environments work.
          </SheetDescription>
        </SheetHeader>

        <SheetBody>
          <Accordion type="multiple" defaultValue={['demos']}>
            <AccordionItem value="demos">
              <AccordionTrigger>Demos</AccordionTrigger>
              <AccordionContent className="flex flex-col gap-0.5">
                <PanelHeading>Live now</PanelHeading>
                {live.map((demo) => (
                  <SheetClose asChild key={demo.slug}>
                    <DemoRow demo={demo} />
                  </SheetClose>
                ))}
                <PanelHeading>Shipping next</PanelHeading>
                {spec.map((demo) => (
                  <SheetClose asChild key={demo.slug}>
                    <DemoRow demo={demo} muted />
                  </SheetClose>
                ))}
                <SheetClose asChild>
                  <Link
                    to="/demos"
                    className="tap inline-flex items-center gap-1 p-2.5 text-xs font-medium text-accent-fg"
                  >
                    Browse all demos
                    <ArrowRight aria-hidden="true" className="size-3.5" />
                  </Link>
                </SheetClose>
              </AccordionContent>
            </AccordionItem>

            <AccordionItem value="verticals">
              <AccordionTrigger>Verticals</AccordionTrigger>
              <AccordionContent className="flex flex-col gap-0.5">
                {verticals.map((vertical) => (
                  <SheetClose asChild key={vertical.slug}>
                    <Link
                      to={routes.vertical(vertical.slug)}
                      className="flex gap-3 rounded-lg p-2.5 hover:bg-surface-2"
                    >
                      <DemoIcon name={vertical.icon} className="mt-0.5 text-accent-fg" />
                      <span className="flex min-w-0 flex-col gap-0.5">
                        <span className="text-sm font-medium text-fg">{vertical.title}</span>
                        <span className="text-xs leading-relaxed text-muted">
                          {vertical.persona}
                        </span>
                      </span>
                    </Link>
                  </SheetClose>
                ))}
              </AccordionContent>
            </AccordionItem>

            <AccordionItem value="how">
              <AccordionTrigger>How it works</AccordionTrigger>
              <AccordionContent className="flex flex-col gap-3">
                <dl className="flex flex-col gap-3">
                  {CONCEPTS.map((concept) => (
                    <div key={concept.term} className="flex flex-col gap-0.5">
                      <dt className="text-sm font-medium text-fg">{concept.term}</dt>
                      <dd className="text-xs leading-relaxed text-muted">{concept.gloss}</dd>
                    </div>
                  ))}
                </dl>
                <TasksetSource />
              </AccordionContent>
            </AccordionItem>
          </Accordion>

          <a
            href={PIG_URL}
            target="_blank"
            rel="noreferrer noopener"
            className="tap mt-2 flex items-center justify-between border-b border-border py-3 text-sm font-medium text-fg"
          >
            primeintellectgrowth.com
            <ArrowUpRight aria-hidden="true" className="size-4 text-muted" />
          </a>
          <a
            href={REPO_URL}
            target="_blank"
            rel="noreferrer noopener"
            className="tap flex items-center justify-between border-b border-border py-3 text-sm font-medium text-fg"
          >
            Source on Gitea
            <GitBranch aria-hidden="true" className="size-4 text-muted" />
          </a>

          <div className="flex items-center gap-1 pt-3">
            <ThemeToggle />
            <ContrastToggle />
          </div>
        </SheetBody>

        <SheetFooter>
          <SheetClose asChild>
            <Button asChild size="lg" className="w-full">
              <Link to={ctaHref}>Play the demo</Link>
            </Button>
          </SheetClose>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}

/* ------------------------------------------------------------------ header */

export function SiteHeader() {
  const { live, spec, verticals, ctaHref } = useLineup();

  return (
    <header
      // The height token already folds in --safe-top, so the padding and the
      // height come from the same source and a notch cannot push the row off
      // the bottom edge of the bar.
      className="sticky top-0 z-50 h-[var(--app-header-h)] border-b border-border bg-surface/80 pt-[var(--safe-top)] backdrop-blur-md supports-[backdrop-filter]:bg-surface/70"
    >
      <div className="mx-auto flex h-full max-w-canvas items-center gap-2 px-4 pl-[max(1rem,var(--safe-left))] pr-[max(1rem,var(--safe-right))]">
        <Link
          to="/"
          className="tap flex shrink-0 items-center rounded-md pr-2 text-base"
          aria-label="PIG demo, home"
        >
          <Wordmark />
        </Link>

        {/*
          `h-full` is not cosmetic. The viewport hangs off the Root's
          `top-full`, so a Root only as tall as its 36px triggers drops the
          panel INSIDE the header, over its own bottom border.
        */}
        <NavigationMenu className="hidden h-full lg:flex" delayDuration={120}>
          <NavigationMenuList>
            <NavigationMenuItem>
              <NavigationMenuTrigger>Demos</NavigationMenuTrigger>
              <NavigationMenuContent>
                <DemosPanel live={live} spec={spec} />
              </NavigationMenuContent>
            </NavigationMenuItem>

            <NavigationMenuItem>
              <NavigationMenuTrigger>Verticals</NavigationMenuTrigger>
              <NavigationMenuContent>
                <VerticalsPanel verticals={verticals} />
              </NavigationMenuContent>
            </NavigationMenuItem>

            <NavigationMenuItem>
              <NavigationMenuTrigger>How it works</NavigationMenuTrigger>
              <NavigationMenuContent>
                <HowItWorksPanel ctaHref={ctaHref} />
              </NavigationMenuContent>
            </NavigationMenuItem>

            <NavigationMenuItem>
              <NavigationMenuLink
                href={PIG_URL}
                target="_blank"
                rel="noreferrer noopener"
                className={cn(navigationMenuTriggerStyle(), 'text-muted hover:text-fg')}
              >
                primeintellectgrowth.com
                <ArrowUpRight aria-hidden="true" className="size-3.5" />
              </NavigationMenuLink>
            </NavigationMenuItem>
          </NavigationMenuList>
        </NavigationMenu>

        <div className="ml-auto flex items-center gap-1">
          <div className="hidden items-center gap-1 lg:flex">
            <ThemeToggle />
            <ContrastToggle />
            <Button asChild variant="ghost" size="icon">
              <a
                href={REPO_URL}
                target="_blank"
                rel="noreferrer noopener"
                aria-label="Source on Gitea"
              >
                <GitBranch aria-hidden="true" />
              </a>
            </Button>
          </div>

          <Button asChild size="touch" className="hidden lg:inline-flex">
            <Link to={ctaHref}>Play the demo</Link>
          </Button>

          <div className="lg:hidden">
            <MobileNav live={live} spec={spec} verticals={verticals} ctaHref={ctaHref} />
          </div>
        </div>
      </div>
    </header>
  );
}
