"use client";

import { useId, useState } from "react";
import { safeParseProgramRepr } from "../lib/programRepr";

interface Props {
  text: string;
  onTextChange: (next: string) => void;
  onDraw: (repr: string, label: string) => void;
}

const PLACEHOLDER =
  "Combine(Reduce(Select(M,[g05347,g00048]),mean),Reduce(Select(M,[g06271]),max),sub)";

export default function PasteToDraw({ text, onTextChange, onDraw }: Props) {
  const [error, setError] = useState<string | null>(null);
  const [showFormat, setShowFormat] = useState(false);
  const panelId = useId();

  function draw() {
    const trimmed = text.trim();
    if (!trimmed) {
      setError("Paste a program first.");
      return;
    }
    const { ok, error: pErr } = safeParseProgramRepr(trimmed);
    if (!ok) {
      setError(`Couldn't parse: ${pErr}`);
      return;
    }
    setError(null);
    onDraw(trimmed, "pasted program");
  }

  return (
    <div>
      <label
        className="mb-1 block text-[11px] font-medium tracking-wide text-muted"
        htmlFor={`${panelId}-textarea`}
      >
        Paste a program
      </label>
      <textarea
        id={`${panelId}-textarea`}
        value={text}
        onChange={(e) => onTextChange(e.target.value)}
        placeholder={PLACEHOLDER}
        spellCheck={false}
        rows={2}
        className="w-full rounded-md border border-border bg-white px-3 py-2 font-mono text-xs text-ink focus:border-accent focus:outline-none"
      />
      <p className="mt-1 text-[11px] text-muted">
        Paste a program here, or click any tile to load it. Use Copy to grab
        a program&apos;s text. Reveal / evaluate is only available for actual
        run winners — pasted programs render as opaque IDs only.
      </p>
      <div className="mt-2 flex items-center justify-end gap-3">
        <button
          type="button"
          onClick={draw}
          className="rounded-md bg-accent px-3 py-1.5 text-xs font-medium text-card hover:bg-ink"
        >
          Draw
        </button>
      </div>
      {error && (
        <p className="mt-2 rounded-md border border-highlight/40 bg-highlight/10 px-3 py-2 text-xs text-highlight">
          {error}
        </p>
      )}
      <div className="mt-3 text-xs">
        <button
          type="button"
          onClick={() => setShowFormat((v) => !v)}
          aria-expanded={showFormat}
          aria-controls={`${panelId}-format`}
          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: showFormat ? "rotate(90deg)" : "rotate(0deg)",
            }}
          >
            ▸
          </span>
          <span className="font-medium">Format &amp; examples</span>
        </button>
        {showFormat && <FormatGuide id={`${panelId}-format`} />}
      </div>
    </div>
  );
}

function FormatGuide({ id }: { id: string }) {
  return (
    <div
      id={id}
      className="mt-3 rounded-md border border-border bg-bg p-4 text-[12.5px] leading-relaxed text-ink"
    >
      <p className="mb-3">
        <strong>What a program is:</strong> a recipe that turns gene
        expression into ONE score per patient.
      </p>
      <p className="mb-2 font-semibold text-ink">The pieces:</p>
      <ul className="mb-3 ml-5 list-disc space-y-1 marker:text-muted">
        <li>
          <code className="font-mono text-ink">M</code> — the expression
          matrix (all patients × genes); the starting data.
        </li>
        <li>
          <code className="font-mono text-ink">Select(M, [g#####, ...])</code>{" "}
          — pick a group of genes → a smaller matrix.
        </li>
        <li>
          <code className="font-mono text-ink">Search(M, k)</code> — bounded
          nested search: keep the top-k columns by univariate target
          association (gated; experimental).
        </li>
        <li>
          <code className="font-mono text-ink">Reduce(&lt;matrix&gt;, &lt;agg&gt;)</code>{" "}
          — collapse a matrix into one score per patient. {" "}
          <code className="font-mono text-ink">&lt;agg&gt;</code> ={" "}
          <code className="font-mono text-ink">mean</code> |{" "}
          <code className="font-mono text-ink">median</code> |{" "}
          <code className="font-mono text-ink">max</code> |{" "}
          <code className="font-mono text-ink">min</code> |{" "}
          <code className="font-mono text-ink">var</code>.
        </li>
        <li>
          <code className="font-mono text-ink">Combine(&lt;scoreA&gt;, &lt;scoreB&gt;, &lt;op&gt;)</code>{" "}
          — merge two scores into one.{" "}
          <code className="font-mono text-ink">&lt;op&gt;</code> ={" "}
          <code className="font-mono text-ink">add</code> |{" "}
          <code className="font-mono text-ink">sub</code> |{" "}
          <code className="font-mono text-ink">mul</code> |{" "}
          <code className="font-mono text-ink">protected_div</code> (safe) |{" "}
          <code className="font-mono text-ink">mean</code>.
        </li>
        <li>
          <code className="font-mono text-ink">Split(&lt;score&gt;, &lt;predicate&gt;)</code>{" "}
          — partition patients into two branches by a name-blind predicate
          (<code className="font-mono text-ink">score</code> = above /
          below median; <code className="font-mono text-ink">stage_late</code>{" "}
          = AJCC stage III/IV), mean-centre per side, then recombine. One
          level of Split only.
        </li>
        <li>
          <code className="font-mono text-ink">FitApply(&lt;score&gt;, &lt;target&gt;)</code>{" "}
          — train a small model on the score against the chosen label
          (<code className="font-mono text-ink">msi</code> or{" "}
          <code className="font-mono text-ink">tmb</code>) and emit
          predicted probabilities / values back to the program.
        </li>
        <li>
          <code className="font-mono text-ink">Associate(&lt;score&gt;, &lt;target&gt;, &lt;kind&gt;)</code>{" "}
          — Scalar output: plain observational correlation against the
          target. <code className="font-mono text-ink">&lt;kind&gt;</code>{" "}
          = <code className="font-mono text-ink">spearman</code> |{" "}
          <code className="font-mono text-ink">pearson</code>.
        </li>
        <li>
          <code className="font-mono text-ink">Effect(&lt;score&gt;, &lt;target&gt;, &lt;kind&gt;)</code>{" "}
          — Scalar output: same correlation AFTER residualising on the
          named clinical confounders (stage + age). Observational
          backdoor adjustment — only as good as the measured confounders.
        </li>
        <li>
          <strong>Output:</strong> one score per patient (or a Scalar for
          Associate / Effect-rooted programs), used to satisfy the
          objective.
        </li>
      </ul>
      <p className="mb-2 font-semibold text-ink">Rules:</p>
      <ul className="mb-3 ml-5 list-disc space-y-1 marker:text-muted">
        <li>
          Gene IDs are the opaque{" "}
          <code className="font-mono text-ink">g#####</code> IDs shown on
          the tiles and in the result.
        </li>
        <li>
          List a <code className="font-mono text-ink">Select</code>&apos;s
          genes in <code className="font-mono text-ink">[square brackets]</code>
          , comma-separated.
        </li>
        <li>Spaces are optional — paste with or without them.</li>
        <li>
          Every <code className="font-mono text-ink">Reduce</code> should
          wrap a <code className="font-mono text-ink">Select(...)</code> so it
          reduces a chosen group, not the whole matrix.
        </li>
      </ul>
      <p className="mb-1 font-semibold text-ink">Annotated example:</p>
      <p className="mb-1 font-mono text-[12px] text-ink">
        Combine(
        <br />
        &nbsp;&nbsp;Reduce(Select(M,[g05347,g00048]), mean),
        <br />
        &nbsp;&nbsp;Reduce(Select(M,[g06271]), max),
        <br />
        &nbsp;&nbsp;sub
        <br />)
      </p>
      <p className="text-muted">
        → average g05347 &amp; g00048 → scoreA; take the max of g06271 →
        scoreB; final score = scoreA − scoreB.
      </p>
    </div>
  );
}
