/* ========================================================================
   sso.jsx — Single Sign-On (Story 7)
   Setup happens in the WorkOS hosted portal, so MILO owns the handoff, the
   connection states, enforcement policy and sign-in. The supplier is named
   once, at the handoff, and never on a member facing surface.
   ======================================================================== */
const { useState: uO, useEffect: eO } = React;

const BREAK_GLASS = "The Account Owner keeps a password and two-factor authentication as emergency access, so a problem with your identity provider can never lock your organisation out.";
const PROVIDER_LINE = "Works with Microsoft Entra ID, Google Workspace, Okta and others.";

/* ---------- Store ---------- */
const SSO_KEY = "mp_sso_v1";
let SS = {
  state: "off",              /* off | setup | active | attention */
  enforcement: "optional",
  provider: "Microsoft Entra ID",
  domain: "acmeco.co.uk",
  sentTo: null,
  sentAt: null,
  openedAt: null
};
try { const raw = localStorage.getItem(SSO_KEY); if (raw) SS = { ...SS, ...JSON.parse(raw) }; } catch (e) {}
const ssoSubs = new Set();
function ssoNotify() {
  try { localStorage.setItem(SSO_KEY, JSON.stringify(SS)); } catch (e) {}
  ssoSubs.forEach((cb) => cb());
}
function useSso() {
  const [, force] = uO(0);
  eO(() => { const cb = () => force((n) => n + 1); ssoSubs.add(cb); return () => ssoSubs.delete(cb); }, []);
  return SS;
}
/* One control drives the card, the sign-in screen and the Security tab. */
function setSsoState(v) {
  if (v === "off") SS = { ...SS, state: "off", sentTo: null, sentAt: null, openedAt: null };
  else if (v === "setup") SS = { ...SS, state: "setup", openedAt: new Date().toISOString(), sentTo: null };
  else if (v === "attention") SS = { ...SS, state: "attention" };
  else SS = { ...SS, state: "active", enforcement: v === "required" ? "required" : "optional" };
  ssoNotify();
}
const isActive = () => SS.state === "active";
const isRequired = () => isActive() && SS.enforcement === "required";

/* Who signs in with SSO: members on the connected domain, or everyone once
   it is required. Derived, so no membership data is invented. */
const RM = () => window.MP_MEMBERS || window.MEMBERS || [];
function ssoMembers() {
  const active = RM().filter((m) => m.status === "active");
  if (isRequired()) return active;
  return active.filter((m) => (m.email || "").toLowerCase().endsWith("@" + SS.domain));
}
/* The owner always keeps a password, so they are never SSO managed. */
/* Under Optional people can still use a password, so their controls stay.
   The notice replaces them only once SSO is the only way in. */
function isSsoManaged(member) {
  if (!isRequired() || !member) return false;
  if (member.role === "owner") return false;
  return ssoMembers().some((m) => m.id === member.id);
}

const fmtDay = (iso) => iso ? new Date(iso).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" }) : null;

/* ---------- Setup handoff ---------- */
function SetupHandoffPanel({ onClose }) {
  const ctx = window.useRoles ? window.useRoles() : null;
  const [mode, setMode] = uO(null);
  const [email, setEmail] = uO(SS.sentTo || "");
  const [err, setErr] = uO(null);
  const [opening, setOpening] = uO(false);
  eO(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });

  const me = ctx ? ctx.actor : null;
  const suggestions = RM().filter((m) => m.status === "active" && (!me || m.id !== me.id)).slice(0, 4);

  const openPortal = () => {
    setOpening(true);
    setTimeout(() => {
      setSsoState("setup");
      onClose();
      if (ctx) ctx.toast({ kind: "ok", title: "Setup portal opened", body: "We will confirm on this page as soon as your identity provider is connected." });
    }, 1600);
  };
  const sendLink = () => {
    if (!window.EMAIL_RE.test(email)) return setErr("Enter a valid email address.");
    SS = { ...SS, state: "setup", sentTo: email.toLowerCase(), sentAt: new Date().toISOString(), openedAt: null };
    ssoNotify();
    onClose();
    if (ctx) ctx.toast({ kind: "ok", title: "Setup link sent", body: "We have emailed " + email.toLowerCase() + " a link to connect your identity provider." });
  };

  if (opening) return (
    <div className="mp-modal-overlay">
      <div className="mp-modal" style={{ maxWidth: 440 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="key-round" size={20} /></div>
        <h3 className="mp-modal-title">Opening the setup portal</h3>
        <p className="mp-modal-sub">Taking you to our secure setup portal. Keep this page open, we will confirm here when setup is complete.</p>
        <div className="mp-modal-actions"><span className="mp-working"><span className="mp-spin-ring" />Opening</span></div>
      </div>
    </div>);

  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal mp-modal--wide" onClick={(e) => e.stopPropagation()}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="key-round" size={20} /></div>
        <h3 className="mp-modal-title">Set up single sign-on</h3>
        <p className="mp-modal-sub">Setup takes a few minutes and happens in our secure setup portal. You will need admin access to your identity provider.</p>

        <div className="mp-sso-paths">
          <button type="button" className={"mp-sso-path" + (mode === "self" ? " is-selected" : "")} onClick={() => { setMode("self"); setErr(null); }}>
            <span className="mp-sso-path-ic"><Icon name="key-round" size={18} /></span>
            <span className="mp-sso-path-body">
              <span className="mp-sso-path-name">I manage our identity provider</span>
              <span className="mp-sso-path-msg">Open the setup portal now and connect it yourself.</span>
            </span>
          </button>
          <button type="button" className={"mp-sso-path" + (mode === "delegate" ? " is-selected" : "")} onClick={() => { setMode("delegate"); setErr(null); }}>
            <span className="mp-sso-path-ic"><Icon name="mail" size={18} /></span>
            <span className="mp-sso-path-body">
              <span className="mp-sso-path-name">Someone else manages it</span>
              <span className="mp-sso-path-msg">Send them a setup link to do it for you.</span>
            </span>
          </button>
        </div>

        {mode === "delegate" ?
        <div className="mp-sso-delegate">
          <div className="mp-field">
            <label className="mp-field-label">Who should we send it to?</label>
            <input className="mp-field-input" type="email" value={email} placeholder="name@acmeco.co.uk"
              onChange={(e) => { setEmail(e.target.value); setErr(null); }} />
            <div className="mp-field-help">The link is valid for five minutes, so ask them to open it when they are ready. If it expires they can request a new one from the email.</div>
            {err ? <div className="mp-inline-err"><Icon name="triangle-alert" size={13} /><span>{err}</span></div> : null}
          </div>
          <div className="mp-sso-suggest">
            {suggestions.map((m) =>
              <button type="button" key={m.id} className="mp-sso-suggest-btn" onClick={() => { setEmail(m.email); setErr(null); }}>
                <Avatar initials={m.initials} size={22} tone={"role-" + m.role} />{m.name}
              </button>)}
          </div>
        </div> : null}

        <p className="mp-sso-powered">Powered by <strong>WorkOS</strong>.</p>

        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          {mode === "delegate" ?
            <Button variant="primary" onClick={sendLink}>Email the Setup Link</Button> :
            <Button variant="primary" className={mode === "self" ? "" : "is-disabled"}
              onClick={mode === "self" ? openPortal : undefined}>Open Setup Portal</Button>}
        </div>
      </div>
    </div>);
}

/* ---------- Enforcement ---------- */
function EnforcementModal({ onClose }) {
  const ctx = window.useRoles ? window.useRoles() : null;
  const [pick, setPick] = uO(SS.enforcement);
  const [confirming, setConfirming] = uO(false);
  eO(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });

  const apply = () => {
    SS = { ...SS, enforcement: pick };
    ssoNotify();
    onClose();
    if (ctx) ctx.toast({ kind: "ok", title: "Enforcement updated",
      body: pick === "required" ? "Everyone signs in with single sign-on from now on." : "People can sign in with single sign-on or with their email and password." });
  };

  if (confirming) return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
        <div className="mp-modal-ic mp-modal-ic--clay"><Icon name="key-round" size={20} /></div>
        <h3 className="mp-modal-title">Require single sign-on for everyone?</h3>
        <p className="mp-modal-text">This changes how your team signs in the next time they visit. Passwords will no longer work for members.</p>
        <div className="mp-wiz-note">
          <Icon name="info" size={15} />
          <span>{BREAK_GLASS}</span>
        </div>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={() => setConfirming(false)}>Back</Button>
          <Button variant="primary" onClick={apply}>Require Single Sign-On</Button>
        </div>
      </div>
    </div>);

  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 470 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="key-round" size={20} /></div>
        <h3 className="mp-modal-title">Change enforcement</h3>
        <div className="mp-sso-paths mp-sso-paths--stack">
          <button type="button" className={"mp-sso-path" + (pick === "optional" ? " is-selected" : "")} onClick={() => setPick("optional")}>
            <span className="mp-sso-path-body">
              <span className="mp-sso-path-name">Optional (rolling out)</span>
              <span className="mp-sso-path-msg">People can sign in either way while you move everyone across to your identity provider.</span>
            </span>
          </button>
          <button type="button" className={"mp-sso-path" + (pick === "required" ? " is-selected" : "")} onClick={() => setPick("required")}>
            <span className="mp-sso-path-body">
              <span className="mp-sso-path-name">Required (recommended)</span>
              <span className="mp-sso-path-msg">Everyone signs in with SSO.</span>
            </span>
          </button>
        </div>
        {pick === "required" ?
        <div className="mp-wiz-note">
          <Icon name="info" size={15} />
          <span>{BREAK_GLASS}</span>
        </div> : null}
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" className={pick === SS.enforcement ? "is-disabled" : ""}
            onClick={pick === SS.enforcement ? undefined : (pick === "required" ? () => setConfirming(true) : apply)}>Save Enforcement</Button>
        </div>
      </div>
    </div>);
}

function DisableSsoModal({ onClose }) {
  const ctx = window.useRoles ? window.useRoles() : null;
  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
        <div className="mp-modal-ic mp-modal-ic--danger"><Icon name="triangle-alert" size={20} /></div>
        <h3 className="mp-modal-title">Turn off single sign-on?</h3>
        <p className="mp-modal-text">Members will sign in with their email address and password instead. Anyone without a password will be asked to set one the next time they sign in.</p>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Keep Single Sign-On</Button>
          <Button variant="danger-solid" onClick={() => {
            setSsoState("off");
            onClose();
            if (ctx) ctx.toast({ kind: "ok", title: "Single sign-on turned off", body: "Your team signs in with email and password from now on." });
          }}>Disable Single Sign-On</Button>
        </div>
      </div>
    </div>);
}

function TestSignInModal({ onClose }) {
  const [phase, setPhase] = uO("working");
  eO(() => { const t = setTimeout(() => setPhase("ok"), 1500); return () => clearTimeout(t); }, []);
  eO(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });
  return (
    <div className="mp-modal-overlay" onClick={phase === "ok" ? onClose : undefined}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className={"mp-modal-ic " + (phase === "ok" ? "mp-modal-ic--mint" : "mp-modal-ic--neutral")}>
          <Icon name={phase === "ok" ? "circle-check" : "key-round"} size={20} />
        </div>
        <h3 className="mp-modal-title">{phase === "ok" ? "Single sign-on is working" : "Testing single sign-on"}</h3>
        <p className="mp-modal-sub">{phase === "ok" ?
          "We reached " + SS.provider + " and came back successfully. Your team can sign in." :
          "Taking you to " + SS.provider + " and back again."}</p>
        <div className="mp-modal-actions">
          {phase === "ok" ?
            <Button variant="primary" onClick={onClose}>Close</Button> :
            <span className="mp-working"><span className="mp-spin-ring" />Testing</span>}
        </div>
      </div>
    </div>);
}

/* ---------- The card on Settings › Organisation ---------- */
function SsoCard() {
  useSso();
  const ctx = window.useRoles ? window.useRoles() : null;
  const [panel, setPanel] = uO(null);
  eO(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });
  /* Organisation identity is Account Owner only, and so is this. */
  if (!ctx || !ctx.can("org.identity")) return null;

  const close = () => setPanel(null);

  return (
    <>
      <Card>
        <div className="mp-acc-body" style={{ paddingTop: 26 }}>
          <div className="mp-zone-head">
            <div>
              <h3 className="mp-acc-title">Single Sign-On</h3>
              <p className="mp-acc-sub">{SS.state === "off" ?
                <>Let your team sign in with your organisation's identity provider instead of a separate password. {PROVIDER_LINE}</> :
                SS.state === "setup" ? "Setup is underway. We will confirm here as soon as your identity provider is connected." :
                SS.state === "attention" ? "Your team cannot sign in with single sign-on at the moment. Your identity provider stopped accepting our connection, so it needs setting up again." :
                "Your team signs in with your organisation's identity provider."}</p>
            </div>
            {SS.state === "active" ? <Badge variant="ok" icon="circle-check">Active</Badge> : null}
            {SS.state === "setup" ? <Badge variant="pending" icon="loader">Setup in progress</Badge> : null}
            {SS.state === "attention" ? <Badge variant="warn" icon="triangle-alert">Needs attention</Badge> : null}
          </div>

          {SS.state === "setup" ?
          <div className="mp-sso-facts">
            <span><Icon name={SS.sentTo ? "mail" : "external-link"} size={14} />{SS.sentTo ?
              <>Sent to <strong>{SS.sentTo}</strong>, {fmtDay(SS.sentAt)}</> :
              <>Portal opened {fmtDay(SS.openedAt)}</>}</span>
          </div> : null}

          {SS.state === "active" ?
          <div className="mp-sso-facts">
            <span><Icon name="key-round" size={14} />{SS.provider}</span>
            <span><Icon name="globe" size={14} />{SS.domain}</span>
            <span><Icon name="lock" size={14} />{SS.enforcement === "required" ? "Required for everyone" : "Optional"}</span>
          </div> : null}

          <div className="mp-acc-foot" style={{ justifyContent: "flex-start", flexWrap: "wrap", gap: 10 }}>
            {SS.state === "off" ?
              <Button variant="primary" icon="key-round" onClick={() => setPanel("setup")}>Set Up Single Sign-On</Button> : null}
            {SS.state === "setup" ?
              <>
                <Button variant="secondary" icon="mail" onClick={() => setPanel("setup")}>Send a New Link</Button>
                <Button variant="secondary" onClick={() => {
                  const sent = SS.sentTo;
                  setSsoState("off");
                  if (ctx) ctx.toast({ kind: "ok", title: "Setup cancelled",
                    body: sent ? "The link sent to " + sent + " no longer works. You can start again whenever you are ready." : "You can start again whenever you are ready." });
                }}>Cancel Setup</Button>
              </> : null}
            {SS.state === "active" ?
              <>
                <Button variant="secondary" icon="key-round" onClick={() => setPanel("test")}>Test SSO Sign-In</Button>
                <Button variant="secondary" icon="lock" onClick={() => setPanel("enforce")}>Change Enforcement</Button>
                <Button variant="danger" onClick={() => setPanel("disable")}>Disable Single Sign-On</Button>
              </> : null}
            {SS.state === "attention" ?
              <Button variant="primary" icon="key-round" onClick={() => setPanel("setup")}>Set It Up Again</Button> : null}
          </div>
        </div>
      </Card>

      {panel === "setup" ? <SetupHandoffPanel onClose={close} /> : null}
      {panel === "enforce" ? <EnforcementModal onClose={close} /> : null}
      {panel === "disable" ? <DisableSsoModal onClose={close} /> : null}
      {panel === "test" ? <TestSignInModal onClose={close} /> : null}
    </>);
}

/* ---------- Security tab replacement for an SSO managed member ---------- */
function SsoSecurityNotice({ member }) {
  useSso();
  if (!isSsoManaged(member)) return null;
  return (
    <Card>
      <div className="mp-acc-body" style={{ paddingTop: 26 }}>
        <div>
          <h3 className="mp-acc-title">Sign-In</h3>
          <p className="mp-acc-sub">Sign-in is managed by your organisation's identity provider.</p>
        </div>
      </div>
    </Card>);
}
/* The owner's own note, under Required only. */
function SsoOwnerNote() {
  useSso();
  if (!isRequired()) return null;
  return (
    <p className="mp-sso-owner-note">
      <Icon name="info" size={14} />
      <span>Your organisation requires single sign-on. You keep a password and two-factor authentication as emergency access.</span>
    </p>);
}

/* ---------- Sign-in screen ----------
   Members never see the supplier's name, only their own provider. */
function SsoContinueButton({ primary }) {
  const [going, setGoing] = uO(false);
  eO(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });
  if (going) return <div className="mp-sso-going"><span className="mp-spin-ring" />Taking you to your identity provider…</div>;
  return (
    <Button variant={primary ? "primary" : "secondary"} size="lg" icon="key-round"
      onClick={() => { setGoing(true); setTimeout(() => { location.hash = "/dashboard"; }, 1600); }}>Continue with SSO</Button>);
}

Object.assign(window, {
  SsoCard, SsoSecurityNotice, SsoOwnerNote, SsoContinueButton,
  MP_SSO: { useSso, setSsoState, isActive, isRequired, isSsoManaged, ssoMembers, get state() { return SS.state; }, get enforcement() { return SS.enforcement; },
    completeSetup(provider) {
      if (SS.state !== "setup") return false;
      SS = { ...SS, state: "active", enforcement: "optional", provider: provider || SS.provider };
      ssoNotify();
      if (window.MP_TOAST) window.MP_TOAST({ kind: "ok", title: "Single sign-on is connected",
        body: "Your team can now sign in with " + SS.provider + ". Enforcement is optional until you change it." });
      return true;
    } }
});
