// ---------------------------------------------------------------------------
// automation/PresetPlan.tsx — WAVE 25 item 4 (ruling R2b, contract C1):
// WHICH COLUMNS THIS WILL USE, AND WHICH IT WILL CREATE.
//
// The owner's words: *"since this is a global fields all tenant use its really
// just appending it and adding it to the custom database"* — so the Create
// record action's configuration has to SHOW the two lists before anything is
// spent, on whatever database that action names, including a hand-made one.
//
// ⛔ IT RENDERS THE SERVER'S ANSWER AND COMPUTES NOTHING (C1: "the client
// renders this; it does not compute it"). Diffing the preset set against a
// table's columns here would be a second implementation of `ut_ensure`'s merge
// rule — and it would be wrong exactly when the two lists differ, which is the
// only case this panel exists to answer.
//
// ⚠ ITS OWN FILE, AND THAT IS THE BUILDER'S LAW BEING KEPT RATHER THAN BENT.
// `AutomationBuilder` renders SYNCHRONOUSLY from what it was handed (C14 leg 1
// — the ghost fix: a view that can be in two shapes shows you the wrong one).
// This panel genuinely needs a fetch, so it owns one, keeps a FIXED-SHAPE
// skeleton while it is in flight, and never changes the shape of anything above
// it. Exactly the split the Board already makes.
// ---------------------------------------------------------------------------
import { useEffect, useState } from "react";

import { getPresetPlan } from "./automationApi";
import type { PresetPlan as Plan } from "./automationApi";

type Load =
  | { phase: "idle" }
  | { phase: "loading" }
  | { phase: "ready"; plan: Plan }
  | { phase: "error" };

/**
 * ⚠ ONE LINE PER LIST, NOT A TOUR (DESIGN.md 4 / R13). The panel says what will happen and shows
 * the column names; it does not explain what a preset is, why the set is shared across tenants,
 * or what enrichment does. Each of those has a home — the action's own `detail`, the field's grey
 * machine-owned mark, the run log — and repeating them here is the paragraph nobody reads.
 */
function List({ title, fields }: { title: string; fields: Plan["fields"] }) {
  if (!fields.length) return null;
  return (
    <div className="autox-preset-list">
      <p className="autox-preset-head">
        {title} <span className="autox-preset-n">{fields.length}</span>
      </p>
      <div className="autox-preset-chips">
        {fields.map((f) => (
          <span className="autox-preset-chip" key={f.key} title={`${f.key} · ${f.type}`}>
            {f.label}
          </span>
        ))}
      </div>
    </div>
  );
}

export default function PresetPlan({ table }: { table: string }) {
  const [load, setLoad] = useState<Load>({ phase: "idle" });

  useEffect(() => {
    if (!table) {
      setLoad({ phase: "idle" });
      return;
    }
    const ac = new AbortController();
    setLoad({ phase: "loading" });
    getPresetPlan(table, ac.signal)
      .then((plan) => setLoad({ phase: "ready", plan }))
      .catch((e) => {
        if ((e as Error)?.name === "AbortError") return;
        setLoad({ phase: "error" });
      });
    return () => ac.abort();
  }, [table]);

  // ⛔ NO DATABASE, NO CLAIM. With nothing chosen there is no question to answer, so this renders
  // nothing at all rather than an empty heading — a heading over nothing says "there should be
  // something here", which is a different and false statement (R13, and the same reasoning R14
  // applies to the whole Configuration section).
  if (!table || load.phase === "idle") return null;

  if (load.phase === "loading") {
    return (
      <p className="auto-note" role="status">
        <span className="lp-spin" aria-label="Loading" />
      </p>
    );
  }

  // ⚠ HONEST, AND IT DOES NOT GUESS. A failed fetch is not "no columns will be created" — that
  // would be a specific, checkable claim about the user's database, invented to keep a panel
  // tidy ([[no-unverifiable-aggregates]]). It says the server did not answer.
  if (load.phase === "error") {
    return <p className="auto-note">Could not read this database's columns just now.</p>;
  }

  const { plan } = load;
  return (
    <div className="autox-preset">
      {/*
        ⚠ THREE STATES, AND THE FIRST TWO ARE DIFFERENT FACTS. A database that does not exist yet
        (R10's spawn-on-save moment — the action names a table nobody has made) is not the same as
        one that exists and shares none of the columns, even though both render an empty "already
        here" list. The server answers `exists` precisely so this line does not have to infer it
        from a length.
      */}
      {!plan.exists ? (
        <p className="auto-hint">
          This database does not exist yet. Saving makes it, with these columns.
        </p>
      ) : null}
      <List title="Already in this database" fields={plan.willUse} />
      <List title="Will be created" fields={plan.willCreate} />
      {/* Both lists empty on a table that DOES exist means the server offered no preset set at
          all. Saying nothing here would leave the panel looking like it failed to load. */}
      {plan.exists && !plan.willUse.length && !plan.willCreate.length ? (
        <p className="auto-note">This server offered no preset columns.</p>
      ) : null}
    </div>
  );
}
