"use client";

import { useId, useRef, useState } from "react";
import { ParamKey } from "./paramHelpContent";
import { useParamHelp } from "./ParamHelpProvider";

/**
 * "How these parameters relate" — a collapsed disclosure with a clean
 * HTML/flex pipeline diagram inside. Presentation only.
 *
 * Centered single-column layout, max-width 460px, width 100% — never
 * wider than the panel, never overflowing. Each step is a neutral box;
 * between consecutive boxes sits a coloured "pill" naming the
 * parameter(s) that govern that transition, with a calm ↓ between
 * pill and the next box.
 */
export default function ParameterFlow() {
  const [open, setOpen] = useState(false);
  const panelId = useId();
  return (
    <div className="mb-4 -mt-2 text-xs">
      <button
        type="button"
        onClick={() => setOpen((o) => !o)}
        aria-expanded={open}
        aria-controls={panelId}
        className="inline-flex items-center gap-1.5 rounded text-ink hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
      >
        <span
          aria-hidden
          style={{
            display: "inline-block",
            transition: "transform 120ms ease",
            transform: open ? "rotate(90deg)" : "rotate(0deg)",
          }}
        >
          ▸
        </span>
        <span className="font-medium">How these parameters relate</span>
      </button>
      {open && (
        <div id={panelId} className="mt-3 w-full">
          <Pipeline />
          <Legend />
        </div>
      )}
    </div>
  );
}

// ---------- diagram model ------------------------------------------------

type PillKind = "SPACE" | "EFFORT" | "VALIDATION";

interface Box {
  title: string;
  sub?: string;
  amber?: boolean;
}

/** A pill is a list of inline fragments: either a plain string or a
 * {bold} fragment so we can highlight just the parameter name. The
 * bold fragments carry an optional ``paramKey`` — when present, that
 * fragment is rendered as a button that opens the ParamHelp modal. */
type Frag = string | { bold: string; paramKey?: ParamKey };
interface Pill {
  kind: PillKind;
  /** Optional small text prefix (e.g. "↻ " for the loop pill). */
  prefix?: string;
  fragments: Frag[];
}

const PILL_STYLES: Record<PillKind, { bg: string; fg: string }> = {
  SPACE: { bg: "#E7EFF1", fg: "#2C5563" },
  EFFORT: { bg: "#F6ECE0", fg: "#8A4E20" },
  VALIDATION: { bg: "#ECEBE6", fg: "#5A6670" },
};

const BOXES: Box[] = [
  { title: "~20,000 genes", sub: "every gene measured" },
  { title: "Gene pool — N genes", sub: "the shortlist the engine draws from" },
  { title: "One program", sub: "Select → Reduce → Fit" },
  { title: "One generation", sub: "every program scored & ranked" },
  { title: "Winning program" },
  { title: "permutation p", sub: "could this be luck?", amber: true },
];

const PILLS: Pill[] = [
  {
    kind: "SPACE",
    fragments: [
      { bold: "Prefilter top-N", paramKey: "prefilter_n" },
      " — keep the N most promising genes (off by default = all ~20,000)",
    ],
  },
  {
    kind: "SPACE",
    fragments: [
      { bold: "Max sets", paramKey: "max_sets" },
      " × ",
      { bold: "Genes/set", paramKey: "genes_per_set" },
      " — pick 1–2 sets, each ≤ G genes",
    ],
  },
  {
    kind: "EFFORT",
    fragments: [
      { bold: "Population", paramKey: "population" },
      " — programs compete each round · ",
      { bold: "λ", paramKey: "lambda" },
      " — taxes extra genes",
    ],
  },
  {
    kind: "EFFORT",
    prefix: "↻ ",
    fragments: [
      "× ",
      { bold: "Generations", paramKey: "generations" },
      " — breed the best, repeat · ",
      { bold: "Seed", paramKey: "seed" },
      " — fixes the randomness",
    ],
  },
  {
    kind: "VALIDATION",
    fragments: [
      { bold: "Permutations", paramKey: "permutations" },
      " — re-run on N shuffled-label sets",
    ],
  },
];

// ---------- render -------------------------------------------------------

function Pipeline() {
  return (
    <div
      style={{
        maxWidth: 460,
        width: "100%",
        marginInline: "auto",
        display: "flex",
        flexDirection: "column",
        alignItems: "stretch",
        gap: 8,
      }}
    >
      {BOXES.map((b, i) => (
        <div key={`group-${i}`} style={{ display: "contents" }}>
          <BoxRow box={b} />
          {i < PILLS.length && (
            <>
              <PillRow pill={PILLS[i]} />
              <Arrow />
            </>
          )}
        </div>
      ))}
    </div>
  );
}

function BoxRow({ box }: { box: Box }) {
  return (
    <div
      style={{
        width: "100%",
        background: box.amber ? "#FBF1E6" : "#F5F4F0",
        border: `1px solid ${box.amber ? "#BC6B2E" : "#D9D6CE"}`,
        borderRadius: 12,
        padding: "12px 14px",
        textAlign: "center",
        fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
        lineHeight: 1.3,
      }}
    >
      <div
        style={{
          fontSize: 13,
          fontWeight: 600,
          color: "#23303A",
        }}
      >
        {box.title}
      </div>
      {box.sub && (
        <div
          style={{
            marginTop: 2,
            fontSize: 11.5,
            color: "#6E7F8C",
          }}
        >
          {box.sub}
        </div>
      )}
    </div>
  );
}

function PillRow({ pill }: { pill: Pill }) {
  const { bg, fg } = PILL_STYLES[pill.kind];
  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        width: "100%",
      }}
    >
      <div
        style={{
          maxWidth: "92%",
          background: bg,
          color: fg,
          borderRadius: 14,
          padding: "6px 12px",
          fontSize: 12.5,
          lineHeight: 1.35,
          textAlign: "center",
          whiteSpace: "normal",
          overflowWrap: "break-word",
          wordBreak: "normal",
          fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
        }}
      >
        {pill.prefix && (
          <span style={{ marginRight: 2 }} aria-hidden>
            {pill.prefix}
          </span>
        )}
        {pill.fragments.map((f, i) => {
          if (typeof f === "string") return <span key={i}>{f}</span>;
          if (!f.paramKey) {
            return (
              <strong key={i} style={{ fontWeight: 600 }}>
                {f.bold}
              </strong>
            );
          }
          return <ParamPillButton key={i} bold={f.bold} paramKey={f.paramKey} colour={fg} />;
        })}
      </div>
    </div>
  );
}

function ParamPillButton({
  bold,
  paramKey,
  colour,
}: {
  bold: string;
  paramKey: ParamKey;
  colour: string;
}) {
  const ref = useRef<HTMLButtonElement>(null);
  const { open } = useParamHelp();
  return (
    <button
      ref={ref}
      type="button"
      aria-haspopup="dialog"
      aria-label={`About ${bold}`}
      onClick={(e) => {
        e.stopPropagation();
        e.preventDefault();
        open(paramKey, ref.current);
      }}
      style={{
        background: "transparent",
        border: "none",
        padding: 0,
        font: "inherit",
        color: colour,
        fontWeight: 600,
        textDecoration: "underline",
        textDecorationStyle: "dotted",
        textDecorationColor: `${colour}66`,
        textUnderlineOffset: 2,
        cursor: "pointer",
      }}
      onMouseOver={(e) => {
        (e.currentTarget.style as any).textDecorationStyle = "solid";
      }}
      onMouseOut={(e) => {
        (e.currentTarget.style as any).textDecorationStyle = "dotted";
      }}
    >
      {bold}
    </button>
  );
}

function Arrow() {
  return (
    <div
      aria-hidden
      style={{
        textAlign: "center",
        color: "#B9B6AE",
        fontSize: 16,
        lineHeight: 1,
        userSelect: "none",
      }}
    >
      ↓
    </div>
  );
}

function Legend() {
  return (
    <div
      style={{
        maxWidth: 460,
        width: "100%",
        marginInline: "auto",
        marginTop: 12,
        display: "flex",
        flexWrap: "wrap",
        justifyContent: "center",
        gap: "6px 14px",
        fontSize: 11,
        color: "#6E7F8C",
      }}
    >
      <LegendItem fill="#E7EFF1" ink="#2C5563">
        teal = where it searches
      </LegendItem>
      <LegendItem fill="#F6ECE0" ink="#8A4E20">
        amber = how hard it searches
      </LegendItem>
      <LegendItem fill="#ECEBE6" ink="#5A6670">
        grey = validation
      </LegendItem>
    </div>
  );
}

function LegendItem({
  fill,
  ink,
  children,
}: {
  fill: string;
  ink: string;
  children: React.ReactNode;
}) {
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
      <span
        aria-hidden
        style={{
          display: "inline-block",
          width: 10,
          height: 10,
          borderRadius: 999,
          background: fill,
          border: `1px solid ${ink}33`,
        }}
      />
      {children}
    </span>
  );
}
