/* model-discovery.jsx — Card 92-07 + 92-08
 * The BYOK landing form. The user enters endpoint + key, clicks Discover, and the
 * relay's models appear in a dropdown grouped by inferred vendor. The wire protocol is
 * AUTO-DETECTED by the backend (try openai /models, then anthropic) — the user NEVER
 * picks openai/anthropic. Picking a model auto-fills protocol/provider/model; a manual
 * model-id box is the fallback. Then Dispatch.
 *
 * INVARIANTS:
 *  - protocol = the DETECTED wire compat-type (from /relay), NEVER a model's inferred
 *    vendor group. provider = the model's group (cosmetic + baseline-match target).
 *  - apiKey is read from the shared `form`, never copied into local state (keeps the
 *    "cleared after dispatch / never persisted" guarantee).
 *
 * Rendered by app.jsx in place of HeroIntro's form. Hooks aliased (useStateDisc/
 * useMemoDisc) to avoid global-scope collisions across classic Babel scripts.
 */
const { useState: useStateDisc, useMemo: useMemoDisc } = React;
// `tr` is the global i18n helper (window.byokicuTr) declared in app.jsx; used at render
// time, so it's always bound by the time these components mount. (Card 92-10)

function ByokLanding({ form, setForm, onStart, canStart, fading }) {
  const [groups, setGroups] = useStateDisc(null); // null = not run; [] = ran, no usable models
  const [detected, setDetected] = useStateDisc(""); // detected wire protocol
  const [loading, setLoading] = useStateDisc(false);
  const [error, setError] = useStateDisc("");
  const [query, setQuery] = useStateDisc("");

  const canDiscover =
    form.endpoint.trim().startsWith("https://") && form.apiKey.trim().length > 0 && !loading;

  const providerOf = useMemoDisc(() => {
    const map = {};
    (groups || []).forEach((g) => (g.models || []).forEach((m) => { map[m.id] = g.provider; }));
    return map;
  }, [groups]);

  const filteredGroups = useMemoDisc(() => {
    if (!groups) return [];
    const q = query.trim().toLowerCase();
    return groups
      .map((g) => ({ provider: g.provider, models: q ? (g.models || []).filter((m) => String(m.id).toLowerCase().includes(q)) : (g.models || []) }))
      .filter((g) => g.models.length > 0);
  }, [groups, query]);

  // When the endpoint changes, reset everything tied to the PREVIOUS relay — the local
  // discovery state AND the dispatch-bound shared form fields (protocol/provider/model).
  // form.protocol is the SOLE source of truth at dispatch (app.js buildProjectThinkPayload);
  // `detected` only reaches it via select/manual. Without clearing form.protocol/model a
  // protocol committed (or a localStorage-rehydrated value) for relay A survives an edit to
  // relay B and dispatches the wrong wire format on a real key-spending run. Clearing model
  // also drops canStart, forcing a fresh discovery / re-type under the new endpoint.
  const onEndpointChange = (value) => {
    setForm({ ...form, endpoint: value, protocol: "", provider: "", model: "" });
    setDetected("");
    setGroups(null);
    setQuery("");
    setError("");
  };

  const discover = async () => {
    if (!canDiscover) return;
    setLoading(true);
    setError("");
    setGroups(null);
    try {
      const res = await fetch("/api/model-discovery/relay", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        // No protocol → backend AUTO-DETECTS the wire compat-type.
        body: JSON.stringify({ apiEndpoint: form.endpoint.trim(), apiKey: form.apiKey })
      });
      const data = await res.json().catch(() => null);
      if (data && data.supported && Array.isArray(data.groups) && data.groups.length > 0) {
        setGroups(data.groups);
        setDetected(data.protocol || "openai");
        // If an already-entered model is among the freshly-discovered ones, re-stamp its
        // protocol/provider from THIS detection so the dispatched form.protocol always
        // matches the detected badge (closes a cosmetic returning-user divergence).
        const g = data.groups.find((grp) => (grp.models || []).some((m) => m.id === form.model));
        if (g) setForm((f) => ({ ...f, protocol: data.protocol || "openai", provider: g.provider }));
      } else {
        setGroups([]);
        setError((data && data.error) || tr("landing.err.noModels"));
      }
    } catch (e) {
      setGroups([]);
      setError(tr("landing.err.discoveryFailed"));
    } finally {
      setLoading(false);
    }
  };

  const selectModel = (id) => {
    if (!id) return;
    // protocol = DETECTED wire compat-type (never the inferred group); provider = group.
    setForm({ ...form, model: id, provider: providerOf[id] || detected || "openai", protocol: detected || "openai" });
  };

  const manualModel = (id) => {
    // Derive the wire signal from the CURRENT relay's detection ONLY — never stale
    // form.protocol (there is no protocol control to correct it, and a prior relay's
    // or a rehydrated saved value could mismatch this endpoint). Undetected → openai.
    // (anthropic via pure manual entry without discovery is out of scope by decision.)
    setForm({ ...form, model: id, provider: detected || "openai", protocol: detected || "openai" });
  };

  return (
    <div className={`hero-intro${fading ? " fading" : ""}`}>
      <div className="hero-stack">
        <div className="hero-eyebrow"><span className="bug">b</span> {tr("landing.eyebrow")}</div>
        <h1 className="hero-headline">{tr("landing.headline.l1")}<br/>{tr("landing.headline.l2pre")}<span className="phos">{tr("landing.headline.phos")}</span></h1>
        <p className="hero-lede">
          {tr("landing.lede")}
        </p>

        <form className="hero-form" onSubmit={(e) => { e.preventDefault(); if (canStart) onStart(); }}>
          <div className="hero-row">
            <label htmlFor="b-endpoint">{tr("landing.label.endpoint")}</label>
            <input id="b-endpoint" autoComplete="off" placeholder="https://my-relay.example.com/v1"
              value={form.endpoint} onChange={(e) => onEndpointChange(e.target.value)} />
          </div>

          <div className="hero-row two">
            <div>
              <label htmlFor="b-apikey">{tr("landing.label.apikey")}</label>
              <input id="b-apikey" type="password" autoComplete="off" placeholder="sk-…"
                value={form.apiKey} onChange={(e) => setForm({ ...form, apiKey: e.target.value })} />
            </div>
            <div className="discovery-discover-cell">
              <label aria-hidden="true">&nbsp;</label>
              <button type="button" className="discovery-btn" disabled={!canDiscover} onClick={discover}>
                {loading ? tr("landing.btn.discovering") : tr("landing.btn.discover")}
              </button>
            </div>
          </div>

          {error ? <p className="discovery-error">{error}</p> : null}

          {groups && groups.length > 0 ? (
            <div className="hero-row">
              <label htmlFor="b-model-select">
                {tr("landing.label.model")}{detected ? <span className="discovery-detected">{tr("landing.detected.suffix", { protocol: detected })}</span> : null}
              </label>
              <input className="discovery-search" placeholder={tr("landing.ph.search")} value={query}
                onChange={(e) => setQuery(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") e.preventDefault(); }} />
              <select id="b-model-select" className="discovery-select"
                value={providerOf[form.model] ? form.model : ""} onChange={(e) => selectModel(e.target.value)}>
                <option value="">{tr("landing.select.placeholder")}</option>
                {filteredGroups.map((g) => (
                  <optgroup key={g.provider} label={g.provider}>
                    {g.models.map((m) => <option key={m.id} value={m.id}>{m.id}</option>)}
                  </optgroup>
                ))}
              </select>
            </div>
          ) : null}

          <div className="discovery-or">{tr("landing.or")}</div>

          <div className="hero-row">
            <label htmlFor="b-model">{tr("landing.label.modelManual")}</label>
            <input id="b-model" autoComplete="off" placeholder="gpt-4.1"
              value={form.model} onChange={(e) => manualModel(e.target.value)} />
          </div>

          <button className="hero-start" type="submit" disabled={!canStart}>
            <span>{tr("landing.btn.dispatch")}</span><span className="arrow">▶▶</span>
          </button>
          <p className="hero-fine">
            {tr("landing.fine")}
          </p>
        </form>
      </div>
    </div>
  );
}

Object.assign(window, { ByokLanding });
