import { Example } from "@/components/design-system/example";
import { Section } from "@/components/design-system/section";
import { Badge } from "@/components/ui/badge";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { cn } from "@/lib/utils";

import { chart, chartGroupDescription, contrast, hexOf, primitives, semantic, textLevel, uiLevel, type ColorToken } from "./tokens";

const WHITE = "#FFFFFF";

function LevelBadge({ level }: { level: string }) {
  const pass = level !== "Fail";
  return (
    <Badge variant={pass ? "secondary" : "destructive"} className="font-mono tabular-nums">
      {level}
    </Badge>
  );
}

/** Which background a token is judged against, and by which rule. */
function pairing(t: ColorToken): { against: string; againstLabel: string; kind: "text" | "ui" | "decor" | "fill" } {
  const p = t.path;
  // Bright teal and lime are fills that always carry ink text and a label, never a bare shape or foreground.
  if (p === "brand.secondary" || p === "brand.accent") return { against: WHITE, againstLabel: "white (ink text on it)", kind: "fill" };
  if (p === "fg.on.primary") return { against: hexOf("bg.primary"), againstLabel: "bg-primary", kind: "text" };
  if (p === "fg.on.accent") return { against: hexOf("bg.accent"), againstLabel: "bg-accent", kind: "text" };
  if (p === "fg.on.dark") return { against: hexOf("bg.dark"), againstLabel: "bg-dark", kind: "text" };
  if (p === "fg.on.danger") return { against: hexOf("action.danger.default"), againstLabel: "action-danger", kind: "text" };
  const status = /^status\.(\w+)\.text$/.exec(p);
  if (status) return { against: hexOf(`status.${status[1]}.bg`), againstLabel: `status-${status[1]}-bg`, kind: "text" };
  if (p === "fg.disabled") return { against: WHITE, againstLabel: "white (exempt)", kind: "decor" };
  if (p.startsWith("fg.")) return { against: WHITE, againstLabel: "white", kind: "text" };
  if (["border.input.default", "border.focus", "border.input.focus", "border.input.error", "border.strong"].includes(p))
    return { against: WHITE, againstLabel: "white", kind: "ui" };
  if (/^action\.(primary|secondary|danger)\./.test(p) || /^status\.\w+\.fill$/.test(p) || p.startsWith("brand."))
    return { against: WHITE, againstLabel: "white", kind: "ui" };
  return { against: WHITE, againstLabel: "white", kind: "decor" };
}

function Swatch({ hex, className }: { hex: string; className?: string }) {
  return <span className={cn("block size-8 shrink-0 rounded-sm border border-border", className)} style={{ background: hex }} aria-hidden />;
}

export function PrimitivePalette() {
  return (
    <Section
      id="colour-primitives"
      title="Colour primitives"
      description="Raw palette from design/design-tokens.json. Ratios are against white; the badge reads the text rule (AAA 7, AA 4.5, AA large 3). Primitives have no Tailwind utilities on purpose, components use the semantic roles."
    >
      <Example title="Palette" bare>
        <div className="divide-y divide-border">
          {primitives.map(({ hue, steps }) => (
            <div key={hue} className="grid grid-cols-[5rem_1fr] items-start gap-4 px-4 py-3">
              <div className="pt-1 text-xs font-medium capitalize text-foreground">{hue}</div>
              <div className="grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-5">
                {steps.map((s) => {
                  const r = contrast(s.hex, WHITE);
                  return (
                    <div key={s.path} className="flex items-center gap-2.5 rounded-md border border-border p-2">
                      <Swatch hex={s.hex} className="size-10" />
                      <div className="min-w-0 text-xs leading-4">
                        <div className="font-medium text-foreground">{s.name}</div>
                        <div className="font-mono tabular-nums text-muted-foreground">{s.hex}</div>
                        <div className="mt-0.5 flex items-center gap-1.5">
                          <span className="font-mono tabular-nums text-muted-foreground">{r.toFixed(2)}</span>
                          <LevelBadge level={textLevel(r)} />
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      </Example>
    </Section>
  );
}

export function LimeRule() {
  const lime = hexOf("lime.400");
  const dark = hexOf("ink");
  const rLimeOnWhite = contrast(lime, WHITE);
  const rDarkOnLime = contrast(dark, lime);
  return (
    <Section
      id="colour-lime"
      title="Lime accent rule"
      description="Lime is for small brand highlights, as a fill, never a foreground. On white it fails every text threshold, so anything printed on it uses ink (#001110). Bright teal follows the same rule."
    >
      <div className="grid gap-4 md:grid-cols-3">
        <Example title="Lime text on white" description="Fails">
          <p className="rounded-sm bg-white px-3 py-4 text-sm font-semibold" style={{ color: lime }}>
            Complete sale, KES 2,450
          </p>
          <div className="mt-3 flex items-center gap-2 text-xs">
            <span className="font-mono tabular-nums">{rLimeOnWhite.toFixed(2)}:1</span>
            <LevelBadge level={textLevel(rLimeOnWhite)} />
            <span className="text-muted-foreground">needs 4.5:1</span>
          </div>
        </Example>
        <Example title="White text on lime" description="Fails">
          <p className="rounded-sm px-3 py-4 text-sm font-semibold text-white" style={{ background: lime }}>
            Complete sale, KES 2,450
          </p>
          <div className="mt-3 flex items-center gap-2 text-xs">
            <span className="font-mono tabular-nums">{rLimeOnWhite.toFixed(2)}:1</span>
            <LevelBadge level={textLevel(rLimeOnWhite)} />
          </div>
        </Example>
        <Example title="Ink text on lime" description="Correct, fg-on-accent">
          <p className="rounded-sm px-3 py-4 text-sm font-semibold" style={{ background: lime, color: dark }}>
            Complete sale, KES 2,450
          </p>
          <div className="mt-3 flex items-center gap-2 text-xs">
            <span className="font-mono tabular-nums">{rDarkOnLime.toFixed(2)}:1</span>
            <LevelBadge level={textLevel(rDarkOnLime)} />
          </div>
        </Example>
      </div>
    </Section>
  );
}

const GROUPS: { id: string; title: string; match: (t: ColorToken) => boolean }[] = [
  { id: "brand", title: "Brand", match: (t) => t.path.startsWith("brand.") },
  { id: "bg", title: "Background", match: (t) => t.path.startsWith("bg.") },
  { id: "fg", title: "Foreground", match: (t) => t.path.startsWith("fg.") },
  { id: "border", title: "Border", match: (t) => t.path.startsWith("border.") },
  { id: "action", title: "Action", match: (t) => t.path.startsWith("action.") },
  { id: "status", title: "Status", match: (t) => t.path.startsWith("status.") },
  { id: "overlay", title: "Overlay", match: (t) => t.path.startsWith("overlay.") },
];

export function SemanticTokens() {
  return (
    <Section
      id="colour-semantic"
      title="Semantic colour tokens"
      description="Roles components actually use (bg-bg-surface, text-fg-primary, border-border-subtle). Each row is judged against the background it sits on: text pairs by WCAG text thresholds, borders and fills by the 3:1 non-text rule, surfaces and soft borders are decorative."
    >
      {GROUPS.map((g) => {
        const rows = semantic.filter(g.match);
        if (!rows.length) return null;
        return (
          <Example key={g.id} title={g.title} bare>
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-12" />
                  <TableHead>Token</TableHead>
                  <TableHead>Value</TableHead>
                  <TableHead>Primitive</TableHead>
                  <TableHead>Against</TableHead>
                  <TableHead className="text-right">Ratio</TableHead>
                  <TableHead>Result</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {rows.map((t) => {
                  const p = pairing(t);
                  const r = contrast(t.hex, p.against);
                  const result = p.kind === "text" ? textLevel(r) : p.kind === "ui" ? uiLevel(r) : null;
                  return (
                    <TableRow key={t.path}>
                      <TableCell>
                        <Swatch hex={t.hex} className="size-6" />
                      </TableCell>
                      <TableCell className="font-medium">{t.name}</TableCell>
                      <TableCell className="font-mono text-xs">{t.hex}</TableCell>
                      <TableCell className="text-muted-foreground">{t.ref ?? "-"}</TableCell>
                      <TableCell className="text-muted-foreground">{p.againstLabel}</TableCell>
                      <TableCell className="text-right font-mono text-xs">{r.toFixed(2)}</TableCell>
                      <TableCell>
                        {result ? <LevelBadge level={result} /> : <Badge variant="outline">{p.kind === "fill" ? "Fill only" : "Decorative"}</Badge>}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </Example>
        );
      })}
    </Section>
  );
}

export function StatusColours() {
  const kinds = [
    { key: "success", label: "Success", sample: "Paid in full" },
    { key: "warning", label: "Warning", sample: "Low stock, 12 left" },
    { key: "error", label: "Error", sample: "Batch expired" },
    { key: "info", label: "Info", sample: "Prescription pending" },
    { key: "neutral", label: "Neutral", sample: "Draft order" },
  ] as const;
  return (
    <Section id="colour-status" title="Status colours" description="Fill for shapes and progress, bg and border for the surface, text for words. Never the fill as text.">
      <Example title="Success, warning, error, info, neutral" bare>
        <div className="grid gap-px bg-border sm:grid-cols-2 lg:grid-cols-5">
          {kinds.map((k) => {
            const bg = hexOf(`status.${k.key}.bg`);
            const border = hexOf(`status.${k.key}.border`);
            const text = hexOf(`status.${k.key}.text`);
            const fill = hexOf(`status.${k.key}.fill`);
            const r = contrast(text, bg);
            return (
              <div key={k.key} className="bg-card p-4">
                <div className="rounded-md border px-3 py-2.5 text-sm font-medium" style={{ background: bg, borderColor: border, color: text }}>
                  {k.sample}
                </div>
                <div className="mt-3 flex items-center gap-2 text-xs">
                  <span className="size-3 rounded-full" style={{ background: fill }} aria-hidden />
                  <span className="font-medium">{k.label}</span>
                  <span className="ml-auto font-mono tabular-nums text-muted-foreground">{r.toFixed(2)}</span>
                  <LevelBadge level={textLevel(r)} />
                </div>
              </div>
            );
          })}
        </div>
      </Example>
    </Section>
  );
}

export function ChartColours() {
  const group = (g: string) => chart.filter((t) => t.path.startsWith(`${g}.`));
  const series = group("series");
  const seq = group("sequential");
  const div = group("diverging");
  const rest = chart.filter((t) => !/^(series|sequential|diverging|status)\./.test(t.path));
  const methods = ["M-Pesa", "Cash", "Card", "Credit"];
  const shares = [58, 31, 7, 4];
  return (
    <Section id="colour-chart" title="Chart colours" description={chartGroupDescription()}>
      <Example title="Series, in order" description="Ratios against white. Under 3:1 means the chart must show values as labels or a table">
        <div className="space-y-4">
          <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-4">
            {series.map((t) => {
              const r = contrast(t.hex, WHITE);
              return (
                <div key={t.path} className="flex items-center gap-2.5 rounded-md border border-border p-2">
                  <Swatch hex={t.hex} className="size-10" />
                  <div className="min-w-0 text-xs leading-4">
                    <div className="font-medium text-foreground">Series {t.path.split(".")[1]}</div>
                    <div className="font-mono tabular-nums text-muted-foreground">
                      {t.ref} · {t.hex}
                    </div>
                    <div className="mt-0.5 flex items-center gap-1.5">
                      <span className="font-mono tabular-nums text-muted-foreground">{r.toFixed(2)}</span>
                      <Badge variant="outline" className="h-4 px-1 text-[10px]">
                        {r >= 3 ? "Pass 3:1" : "Label it"}
                      </Badge>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
          <div>
            <div className="mb-1.5 flex flex-wrap gap-3 text-xs text-muted-foreground">
              {methods.map((m, i) => (
                <span key={m} className="flex items-center gap-1.5">
                  <span className="size-2.5 rounded-[2px]" style={{ background: series[i]?.hex }} aria-hidden />
                  {m} {shares[i]}%
                </span>
              ))}
            </div>
            <div className="flex h-7 gap-[2px]" role="img" aria-label={methods.map((m, i) => `${m} ${shares[i]}%`).join(", ")}>
              {methods.map((m, i) => (
                <span key={m} className="h-full first:rounded-l-[4px] last:rounded-r-[4px]" style={{ width: `${shares[i]}%`, background: series[i]?.hex }} />
              ))}
            </div>
          </div>
        </div>
      </Example>
      <div className="grid gap-4 lg:grid-cols-2">
        <Example title="Sequential" description={chartGroupDescription("sequential")}>
          <div className="flex gap-[2px]">
            {seq.map((t, i) => (
              <div key={t.path} className="flex-1">
                <div className={cn("h-8", i === 0 && "rounded-l-[4px]", i === seq.length - 1 && "rounded-r-[4px]")} style={{ background: t.hex }} />
                <div className="mt-1 font-mono text-[10px] text-muted-foreground">{t.ref}</div>
              </div>
            ))}
          </div>
        </Example>
        <Example title="Diverging" description={chartGroupDescription("diverging")}>
          <div className="flex gap-[2px]">
            {div.map((t, i) => (
              <div key={t.path} className="flex-1">
                <div className={cn("h-8", i === 0 && "rounded-l-[4px]", i === div.length - 1 && "rounded-r-[4px]")} style={{ background: t.hex }} />
                <div className="mt-1 text-[10px] text-muted-foreground">
                  {t.path.split(".")[1]} · <span className="font-mono">{t.ref}</span>
                </div>
              </div>
            ))}
          </div>
        </Example>
      </div>
      <Example title="Chart chrome and highlight" bare>
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Token</TableHead>
              <TableHead>Value</TableHead>
              <TableHead>Use</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {rest.map((t) => (
              <TableRow key={t.path}>
                <TableCell className="font-mono text-xs">--color-{t.name}</TableCell>
                <TableCell>
                  <span className="flex items-center gap-2 font-mono text-xs">
                    <Swatch hex={t.hex} className="size-4" />
                    {t.ref ?? t.hex}
                  </span>
                </TableCell>
                <TableCell className="text-xs whitespace-normal text-muted-foreground">{t.description}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </Example>
    </Section>
  );
}
