// MostlyPrivacy — "Add your site": the first-run onboarding, in two beats.
//
// WHY IT EXISTS. Adding a site used to be window.prompt(): unstyled, untypeable-into
// on a phone, no validation until the round trip came back, no way to show WHY the
// server said no — and it dropped you back onto an empty table with nothing to do.
// Adding a site is step 1 of 3; the app only ever did step 1.
//
// THE SHAPE. One question, then the payoff:
//   1. Domain — paste anything ("https://www.Example.com/pricing"), we show what will
//      actually be stored, validate with the SAME rule the server uses (shared.jsx
//      normDomain/isDomain), and pick the fallback regime with a sane default so
//      nobody has to answer a second question to get through.
//   2. Install — the real embed snippet carrying the real site key, a copy button
//      that actually copies, and the three things worth doing next, one tap each.
//
// Nothing here invents data: the snippet is built from the created site's own
// siteKey, so what you copy is what will resolve.
(function () {
const F = window.ForgeDesignSystem_e40d74;
const { Button, Dialog, Field, Input } = F;
const { Icon, ICONS, normDomain, isDomain, snippetAttrs, snippetText, SnippetCode, CopyButton } = window.MP;

const api = window.MPApi || { ready: false };

// Server refusals worth a real answer rather than a raw message. createSite throws
// these codes (functions/sites.js); each one has a different way out, so each gets
// its own sentence and, where there is one, a button that takes it.
function explain(e, domain) {
  const code = (e && e.code) || "";
  const msg = (e && e.message) || "";
  if (/already-exists/.test(code) || /already added/i.test(msg)) {
    return { text: domain + " is already on your account.", cta: null };
  }
  if (/resource-exhausted/.test(code)) {
    return { text: "You've used every site your plan includes.", cta: "plans", ctaLabel: "See plans" };
  }
  if (/permission-denied/.test(code) && /organization/i.test(msg)) {
    return { text: msg, cta: "plans", ctaLabel: "Upgrade" };
  }
  if (/unauthenticated/.test(code)) return { text: "Please sign in again to add a site.", cta: null };
  return { text: msg || "Could not add the site. Please try again.", cta: null };
}

// The fallback regime — the model a visitor gets when geo can't place them. It is
// NOT a customer choice about opt-in vs opt-out (that is always resolved from the
// visitor's own regime); it only decides the default, so the label says exactly that.
const REGIMES = [
  { id: "gdpr", label: "EU / UK", sub: "Ask first (opt-in)" },
  { id: "ccpa", label: "United States", sub: "Opt-out" },
];

function AddSiteDialog({ open, onClose, onAdded, nav }) {
  const [raw, setRaw] = React.useState("");
  const [regime, setRegime] = React.useState("gdpr");
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [site, setSite] = React.useState(null);
  const [touched, setTouched] = React.useState(false); // don't scold mid-word

  // Fresh dialog every time it opens — a half-typed domain from last time is noise.
  // (The dialog unmounts while closed, so the field's autoFocus lands on each open.)
  React.useEffect(() => {
    if (!open) return;
    setRaw(""); setRegime("gdpr"); setBusy(false); setErr(null); setSite(null); setTouched(false);
  }, [open]);

  // Escape closes — the browser gave us that for free on prompt(); a dialog has to
  // earn it back.
  React.useEffect(() => {
    if (!open) return undefined;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);

  const domain = normDomain(raw);
  const valid = isDomain(domain);
  // Only worth showing when we changed something — otherwise it just repeats the field.
  const cleaned = valid && domain !== raw.trim().toLowerCase();
  // A disabled button with no reason is a dead end. Say what's missing — but only
  // once they've left the field, never while they're still typing "exa".
  const shapeErr = touched && raw.trim() && !valid
    ? "That needs a domain ending, like " + (domain.replace(/[^a-z0-9-]/g, "") || "example") + ".com"
    : null;

  async function submit() {
    if (!valid || busy) return;
    setBusy(true); setErr(null);
    try {
      const created = await api.createSite(domain, { rules: { default: regime } });
      if (!created) return;                   // signed out → the api gate bounced to sign-in
      setSite(created);
      if (onAdded) onAdded(created);
    } catch (e) {
      setErr(explain(e, domain));
    } finally {
      setBusy(false);
    }
  }

  const goto = (view, id) => { onClose(); if (nav) nav("app", view, id); };

  if (!open) return null;

  // ── beat 2: the payoff ────────────────────────────────────────────────────
  if (site) {
    const attrs = snippetAttrs({ siteKey: site.siteKey || site.id });
    const NEXT = [
      [ICONS.cookie, "Style the banner", "Layout, colours, categories", "banner"],
      [ICONS.doc, "Generate the documents", "Privacy, cookie and terms — 30+ languages", "documents"],
      [ICONS.scan, "Scan for cookies", "Find what the site actually sets", "scanner"],
    ];
    return (
      <Dialog open title={site.domain + " is live"} sub="Paste this before </head> and the banner is running. Everything below can wait." onClose={onClose}
        footer={<Button variant="primary" size="sm" onClick={onClose}>Done</Button>}>
        <div className="bb-code" style={{ marginBottom: 6 }}>
          <div className="bb-code__copy"><CopyButton text={() => snippetText(attrs)} done="Copied" /></div>
          <SnippetCode attrs={attrs} />
        </div>
        <div className="as-next">
          {NEXT.map(([d, t, s, view]) => (
            <button className="wz-scan-cta as-next__row" key={view} onClick={() => goto(view, site.id)}>
              <span className="wz-scan-cta__ic"><Icon d={d} size={17} /></span>
              <span className="wz-scan-cta__body">
                <span className="wz-scan-cta__t">{t}</span>
                <span className="wz-scan-cta__s">{s}</span>
              </span>
              <Icon d={ICONS.arrow} size={15} />
            </button>
          ))}
        </div>
      </Dialog>
    );
  }

  // ── beat 1: the one question ──────────────────────────────────────────────
  return (
    <Dialog open title="Add your site" sub="One domain. The banner, the documents and the consent log all follow from it." onClose={onClose}
      footer={<>
        <Button variant="ghost" size="sm" onClick={onClose}>Cancel</Button>
        <Button variant="primary" size="sm" disabled={!valid || busy} onClick={submit}>
          {busy ? "Adding…" : "Add site"}
        </Button>
      </>}>
      <Field label="Site domain" error={shapeErr} hint={cleaned ? null : "No https://, no www — just the domain."}>
        <Input autoFocus value={raw} placeholder="example.com" autoComplete="off" spellCheck="false"
          invalid={!!shapeErr} icon={<Icon d={ICONS.globe} size={15} />}
          onChange={(e) => { setRaw(e && e.target ? e.target.value : e); if (err) setErr(null); }}
          onBlur={() => setTouched(true)}
          onKeyDown={(e) => { if (e.key === "Enter") { setTouched(true); submit(); } }} />
      </Field>
      {cleaned && (
        <div className="as-cleaned"><Icon d={ICONS.check} size={13} /><span>Adding <b>{domain}</b></span></div>
      )}

      <div className="as-regime">
        <div className="as-regime__label">If we can't tell where a visitor is</div>
        <div className="bb-seg">
          {REGIMES.map((r) => (
            <button key={r.id} className={regime === r.id ? "is-active" : ""} onClick={() => setRegime(r.id)}>
              {r.label} <span className="as-regime__sub">· {r.sub}</span>
            </button>
          ))}
        </div>
        <div className="as-regime__note">Visitors we can place always get their own region's rules — this is only the fallback.</div>
      </div>

      {err && (
        <div className="as-err">
          <Icon d={ICONS.alertTriangle} size={15} />
          <span>{err.text}</span>
          {err.cta === "plans" && <Button variant="secondary" size="sm" onClick={() => { onClose(); if (nav) nav("pricing"); }}>{err.ctaLabel}</Button>}
        </div>
      )}
    </Dialog>
  );
}

// The empty state that opens it — the moment onboarding actually starts, so it
// carries the invitation rather than an blank table.
function NoSitesYet({ onAdd, compact }) {
  return (
    <div className={"as-empty" + (compact ? " as-empty--compact" : "")}>
      <span className="as-empty__ic"><Icon d={ICONS.globe} size={compact ? 20 : 24} /></span>
      <div className="as-empty__t">No sites yet</div>
      <div className="as-empty__s">Add the domain you want covered — it takes one field.</div>
      <Button variant="primary" size="sm" iconLeft={<Icon d={ICONS.plus} size={15} />} onClick={onAdd}>Add your first site</Button>
    </div>
  );
}

window.MP = Object.assign(window.MP || {}, { AddSiteDialog, NoSitesYet });
})();
