"use client";

import { useRef } from "react";
import { motion, useScroll, useTransform, useReducedMotion } from "motion/react";
import { FabricPattern, type FabricKind } from "@/components/media/FabricPattern";
import type { SlotTone } from "@/components/media/MediaSlot";
import { SplitText } from "@/components/motion/SplitText";
import { Reveal } from "@/components/motion/Reveal";

const TONES: Record<SlotTone, React.CSSProperties> = {
  cotton: {
    "--pattern-a": "#141926",
    "--pattern-b": "#1e2637",
    "--pattern-c": "#0a0e18",
    "--pattern-thread": "#f5f1e8",
    "--pattern-glow": "#e0a458",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
  indigo: {
    "--pattern-a": "#0f1734",
    "--pattern-b": "#1b2a5b",
    "--pattern-c": "#060a18",
    "--pattern-thread": "#93a7e8",
    "--pattern-glow": "#3a56a6",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
  thread: {
    "--pattern-a": "#1a1408",
    "--pattern-b": "#2a2110",
    "--pattern-c": "#0a0805",
    "--pattern-thread": "#e0a458",
    "--pattern-glow": "#e0a458",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
  hiviz: {
    "--pattern-a": "#16170b",
    "--pattern-b": "#222310",
    "--pattern-c": "#090a05",
    "--pattern-thread": "#d8e04a",
    "--pattern-glow": "#d8e04a",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
  melange: {
    "--pattern-a": "#171a21",
    "--pattern-b": "#242932",
    "--pattern-c": "#0d1016",
    "--pattern-thread": "#8a8f9c",
    "--pattern-glow": "#8a8f9c",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
  ember: {
    "--pattern-a": "#2a1c11",
    "--pattern-b": "#45301d",
    "--pattern-c": "#140d07",
    "--pattern-thread": "#f0d3a8",
    "--pattern-glow": "#e0a458",
    "--pattern-slub": "#f5f1e8",
  } as React.CSSProperties,
};

/**
 * Inner page hero. The fabric artwork behind the title scales and drifts on
 * scroll, so the page opens with depth rather than a flat banner.
 */
export function PageHero({
  index,
  kicker,
  title,
  lede,
  pattern,
  tone,
  meta,
  patternScale = 1.5,
  scrim = "strong",
}: {
  index?: string;
  kicker: string;
  title: string;
  lede: string;
  pattern: FabricKind;
  tone: SlotTone;
  meta?: Array<{ label: string; value: string }>;
  /**
   * Repeat size of the artwork. The default reads as cloth seen close up. A
   * larger value gives fewer, bolder repeats, which survives the scrim instead
   * of collapsing into a flat mesh.
   */
  patternScale?: number;
  /**
   * How hard the ink gradient sits on the artwork. `strong` is the reading
   * default. `soft` lets the colour through and suits a hero whose job is
   * atmosphere rather than dense copy.
   */
  scrim?: "strong" | "soft";
}) {
  const ref = useRef<HTMLElement>(null);
  const reduced = useReducedMotion();

  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start start", "end start"],
  });

  // The output ranges collapse under reduced motion rather than the style prop
  // being dropped. Both paths start at the same value, so the server rendered
  // markup is identical either way and the parallax simply never travels.
  const scale = useTransform(scrollYProgress, [0, 1], [1, reduced ? 1 : 1.18]);
  const y = useTransform(scrollYProgress, [0, 1], ["0%", reduced ? "0%" : "16%"]);
  const fade = useTransform(scrollYProgress, [0, 0.85], [1, reduced ? 1 : 0]);

  return (
    <section
      ref={ref}
      className="relative isolate flex min-h-[78svh] items-end overflow-hidden bg-[var(--ink)] pb-16 pt-36 md:min-h-[88svh] md:pb-24"
    >
      <motion.div
        className="absolute inset-0 -z-10"
        style={{ scale, y }}
      >
        <FabricPattern
          kind={pattern}
          seed={title.length * 977}
          scale={patternScale}
          className="h-full w-full"
          style={TONES[tone]}
        />
      </motion.div>

      {/* Solid ink at the foot regardless, because that is where the copy sits.
          Only the upper reaches change, which is where the artwork is doing the
          work and nothing has to stay legible. */}
      <div
        className={
          scrim === "soft"
            ? "absolute inset-0 -z-10 bg-gradient-to-t from-[var(--ink)] via-[var(--ink)]/62 to-[var(--ink)]/25"
            : "absolute inset-0 -z-10 bg-gradient-to-t from-[var(--ink)] via-[var(--ink)]/78 to-[var(--ink)]/45"
        }
      />

      <motion.div
        className="shell w-full"
        style={{ opacity: fade }}
      >
        <Reveal direction="none" duration={0.6}>
          <p className="eyebrow flex items-center gap-3">
            {index ? <span className="data">{index}</span> : null}
            <span className="h-px w-8 bg-[var(--thread)]" />
            {kicker}
          </p>
        </Reveal>

        <SplitText
          text={title}
          as="h1"
          className="display-xl mt-6 max-w-5xl text-balance text-[var(--cotton)]"
        />

        <Reveal delay={0.2}>
          <p className="lede mt-8 max-w-2xl text-pretty">{lede}</p>
        </Reveal>

        {meta ? (
          <Reveal delay={0.3}>
            <dl className="mt-12 flex flex-wrap gap-x-12 gap-y-6 border-t border-[var(--rule)] pt-8">
              {meta.map((item) => (
                <div key={item.label}>
                  <dt className="font-mono text-[10px] uppercase tracking-[0.2em] text-[var(--melange)]">
                    {item.label}
                  </dt>
                  <dd className="data mt-2 text-lg text-[var(--cotton)]">
                    {item.value}
                  </dd>
                </div>
              ))}
            </dl>
          </Reveal>
        ) : null}
      </motion.div>
    </section>
  );
}
