/* Error boundary — a transient render error shows a recoverable card,
   never a white screen. */
class ErrorBoundary extends React.Component {
  constructor(p) { super(p); this.state = { err: null }; }
  static getDerivedStateFromError(err) { return { err }; }
  componentDidUpdate(prev) { if (prev.viewKey !== this.props.viewKey && this.state.err) this.setState({ err: null }); }
  render() {
    if (!this.state.err) return this.props.children;
    return (
      <div style={{ maxWidth: 520, margin: "60px auto", textAlign: "center" }}>
        <span style={{ width: 56, height: 56, borderRadius: 15, background: "var(--danger-bg)", display: "inline-grid", placeItems: "center" }}><Icon name="alert-triangle" size={24} color="var(--danger)" /></span>
        <h2 style={{ fontSize: 20, fontWeight: 700, margin: "14px 0 6px" }}>Something hiccuped rendering this view</h2>
        <p style={{ fontSize: 13, color: "var(--fg3)", marginBottom: 18 }}>Your data is safe (saved locally). Reload or switch views to continue.</p>
        <Button variant="primary" icon="rotate-ccw" onClick={() => this.setState({ err: null })}>Try again</Button>
      </div>
    );
  }
}
window.ErrorBoundary = ErrorBoundary;

/* App shell — subscribes to the store, routes between views, owns the modal
   composer and toasts. */
// Persistent nudge shown (live mode) until the signed-in user verifies their email.
function VerifyBanner({ onToast }) {
  const [busy, setBusy] = React.useState(false);
  const [hidden, setHidden] = React.useState(false);
  const live = window.LEAP && window.LEAP.live;
  const user = window.LeapAuth && window.LeapAuth.state ? window.LeapAuth.state().user : null;
  if (!live || hidden || !user || user.emailVerified !== false) return null;
  const resend = () => {
    setBusy(true);
    window.LeapAPI.resendVerification()
      .then((r) => onToast(r && r.sent ? "Verification email sent — check your inbox." : "You're already verified."))
      .catch(() => onToast("Couldn't send the email — please try again.", "error"))
      .finally(() => setBusy(false));
  };
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 16px", background: "var(--warning-weak, #FEF3C7)", borderBottom: "1px solid var(--warning, #F59E0B)", fontSize: 13, color: "var(--fg1, #1F2937)" }}>
      <Icon name="mail" size={16} color="var(--warning-strong, #B45309)" />
      <span style={{ flex: 1 }}>Please verify your email{user.email ? <span> — we sent a link to <b>{user.email}</b></span> : null}.</span>
      <button onClick={resend} disabled={busy} style={{ border: 0, background: "transparent", color: "var(--accent, #0B5FFF)", fontWeight: 700, cursor: "pointer", fontSize: 13, fontFamily: "inherit" }}>{busy ? "Sending…" : "Resend"}</button>
      <button onClick={() => setHidden(true)} title="Dismiss" style={{ border: 0, background: "transparent", cursor: "pointer", color: "var(--fg3, #6B7280)", display: "inline-flex" }}><Icon name="x" size={15} /></button>
    </div>
  );
}

function App() {
  const S = window.CroprStore;
  const [, force] = React.useReducer((x) => x + 1, 0);
  const [active, setActive] = React.useState("dashboard");
  const [editingId, setEditingId] = React.useState(null);
  const [toast, setToast] = React.useState(null);
  const toastTimer = React.useRef(null);

  React.useEffect(() => S.subscribe(() => force()), []);
  // Auth (SSO) + entitlement gate + live data hydrate. Establish the session
  // first; only once authenticated do we load entitlements and pull content.
  // All inert offline.
  React.useEffect(() => {
    const offAuth = window.LeapAuth.subscribe(() => force());
    const offGate = window.LeapGate.subscribe(() => force());
    window.LeapAuth.init().then(() => {
      if (window.LeapAuth.authenticated()) {
        Promise.resolve(window.LeapGate.load()).then(() => { if (window.LeapSync) window.LeapSync.hydrate(); });
      }
    });
    return () => { offAuth(); offGate(); };
  }, []);
  const showToast = (msg, kind) => {
    setToast({ msg, kind: kind || "ok" });
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2800);
  };

  // Landed back from the email verification link → toast + clean the URL.
  React.useEffect(() => {
    try {
      const u = new URL(window.location.href);
      const v = u.searchParams.get("verified");
      if (v === null) return;
      showToast(v === "1" ? "Email verified — you're all set." : "That verification link is invalid or has expired.", v === "1" ? "ok" : "error");
      u.searchParams.delete("verified");
      window.history.replaceState({}, "", u.pathname + (u.search || "") + u.hash);
    } catch (e) { /* ignore */ }
  }, []);

  const posts = S.getAll();
  const open = (id) => setEditingId(id);
  const create = () => { const p = S.create({ status: "idea", title: "Untitled post" }); showToast("New post started — at the Idea stage"); setEditingId(p.id); };
  const addOnDate = (isoDate) => { const p = S.create({ status: "idea", title: "Untitled post", scheduleAt: isoDate }); setEditingId(p.id); };
  const reuse = (id) => { const c = S.duplicate(id); if (c) { showToast("Duplicated as a new draft"); setEditingId(c.id); } };

  const titles = { dashboard: "Dashboard", posts: "Posts", calendar: "Calendar", queue: "Queue",
    campaigns: "Campaigns", pulse: "Pulse Desk", wizards: "Wizards", screener: "X Market Screener", replies: "Reply Engine", clients: "Clients", assets: "Assets", integrations: "Integrations", settings: "Settings" };

  const view = () => {
    // Plan gating (live mode only): a locked view renders the upgrade panel in
    // place of the feature. Offline/demo → lockedView is always false.
    if (window.LeapGate.lockedView(active)) return <UpgradePanel feature={window.LeapGate.VIEW_FEATURE[active]} />;
    switch (active) {
      case "dashboard": return <AnalyticsView posts={posts} onOpen={open} onReuse={reuse} onToast={showToast} onNav={setActive} />;
      case "posts": return <PostsView posts={posts} onOpen={open} onNew={create} onToast={showToast} />;
      case "calendar": return <CalendarView posts={posts} onOpen={open} onAdd={addOnDate} />;
      case "queue": return <QueueView posts={posts} onOpen={open} onToast={showToast} />;
      case "campaigns": return <CampaignsView onToast={showToast} onOpenPost={open} />;
      case "pulse": return <PulseDesk onToast={showToast} onOpen={open} />;
      case "wizards": return <WizardsView onToast={showToast} onNav={setActive} />;
      case "screener": return <ScreenerView watch={S.getWatchAccounts()} feed={S.getScreener()} onToast={showToast} onGotoReplies={() => setActive("replies")} />;
      case "replies": return <RepliesView replies={S.getReplies()} autopilot={S.getAutopilot()} watch={S.getWatchAccounts()} audit={S.getReplyAudit()} onToast={showToast} />;
      case "clients": return <ClientsView onToast={showToast} onNav={setActive} />;
      case "assets": return <AssetsView onToast={showToast} />;
      case "integrations": return <Integrations onToast={showToast} />;
      case "settings": return <SettingsView onToast={showToast} />;
      default: return null;
    }
  };

  // Live SSO gate: until a session is established, show the login screen (or a
  // brief splash while checking). Offline, this never triggers.
  if (window.LEAP && window.LEAP.live) {
    const a = window.LeapAuth.state();
    if (a.status === "unknown") return <div style={{ minHeight: "100vh", display: "grid", placeItems: "center", color: "var(--fg3, #6B7280)", fontSize: 13 }}>Signing you in…</div>;
    if (a.status === "anonymous") return <Login />;
  }

  return (
    <div style={{ display: "flex", height: "100%", background: "var(--bg-subtle)" }}>
      <Sidebar active={active} onNav={setActive} />
      <div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
        <VerifyBanner onToast={showToast} />
        <TopBar title={titles[active]} onNew={create} onOpen={open} onSettings={() => setActive("settings")}
          onReset={() => { if (confirm("Reset all demo data to the seeded set?")) { S.reset(); setEditingId(null); setActive("dashboard"); showToast("Demo data reset"); } }} />
        <main style={{ flex: 1, overflow: "auto", padding: 28 }}><ErrorBoundary viewKey={active}>{view()}</ErrorBoundary></main>
      </div>
      {editingId && <ComposerModal postId={editingId} onClose={() => setEditingId(null)} onToast={showToast} onReuse={reuse} />}
      {!S.getOnboarding().done && <Onboarding onDone={(dest) => { setActive(dest || "dashboard"); setEditingId(null); }} onToast={showToast} />}
      {S.getOnboarding().done && window.Assistant && <Assistant onNav={setActive} />}
      <Toast toast={toast} />
    </div>
  );
}
window.App = App;
