// ---------- Auto-sync com Supabase ----------
// Carrega tudo no mount; em cada mudança no estado, faz diff com snapshot anterior
// e dispara insert/update/delete granulares no banco.
function diffArray(prev, curr, onInserts, onDelete, onUpdate) {
  const prevById = new Map(prev.map(x => [x.id, x]));
  const currById = new Map(curr.map(x => [x.id, x]));
  const inserts = [];
  for (const [id, x] of currById) {
    if (!prevById.has(id)) inserts.push(x);
    else if (JSON.stringify(prevById.get(id)) !== JSON.stringify(x)) onUpdate(id, x);
  }
  for (const [id] of prevById) {
    if (!currById.has(id)) onDelete(id);
  }
  if (inserts.length) onInserts(inserts);
}

function useSupabaseSync(workspaces, setWorkspaces) {
  const [loaded, setLoaded] = React.useState(false);
  const [error, setError] = React.useState(null);
  const prevRef = React.useRef(null);
  const settingsTimers = React.useRef({}); // wsKey -> timeout id (debounce)

  React.useEffect(() => {
    (async () => {
      try {
        let data = await window.db.fetchAll();
        // Primeiro login: tenta adotar dados órfãos (sem user_id) deixados antes do auth
        if (!data || Object.keys(data).length === 0) {
          await window.db.claimOrphanData();
          data = await window.db.fetchAll();
        }
        // Vazio = ok. Usuário cria a primeira conta explicitamente.
        setWorkspaces(data || {});
        prevRef.current = data || {};
        setLoaded(true);
      } catch (err) {
        console.error("[sync] erro ao carregar:", err);
        setError(err);
        setWorkspaces({});
        setLoaded(true);
      }
    })();
  }, []);

  React.useEffect(() => {
    if (!loaded || !prevRef.current || !workspaces) return;
    const prev = prevRef.current;
    const curr = workspaces;

    // ===== SAFETY: snapshot pre-sync no localStorage =====
    // Antes de tocar no DB, salva o estado atual num key fixo.
    // Se algo der errado e perder dados, dá pra recuperar manualmente lendo
    // localStorage.getItem('fin_state_snapshot') no console.
    try {
      const snapshot = JSON.stringify({ at: new Date().toISOString(), workspaces: curr });
      // Rotativo: mantém os 3 últimos snapshots (anteontem/ontem/agora)
      const prevSnap = localStorage.getItem("fin_state_snapshot");
      const prev2 = localStorage.getItem("fin_state_snapshot_prev");
      if (prevSnap) localStorage.setItem("fin_state_snapshot_prev", prevSnap);
      if (prev2)    localStorage.setItem("fin_state_snapshot_prev2", prev2);
      localStorage.setItem("fin_state_snapshot", snapshot);
    } catch (e) { /* QuotaExceeded ok — só descarta se cheio */ }

    for (const wsKey of Object.keys(curr)) {
      const pw = prev[wsKey];
      const cw = curr[wsKey];
      if (!cw) continue;
      if (!pw) {
        if ((cw.transactions || []).length) window.db.insertTransactions(wsKey, cw.transactions);
        if ((cw.receitas || []).length)     window.db.insertIncomes(wsKey, cw.receitas);
        continue;
      }
      // Settings: debounce 600ms (evita flood enquanto usuário digita)
      const settingsKeys = ["name","fullName","accent","accentSoft","icon","logo","monthlyGoal","type","categories","incomeCategories","payments","categoryIcons","categoryImages"];
      if (settingsKeys.some(k => JSON.stringify(pw[k]) !== JSON.stringify(cw[k]))) {
        clearTimeout(settingsTimers.current[wsKey]);
        settingsTimers.current[wsKey] = setTimeout(() => {
          window.db.updateWorkspaceSettings(wsKey, cw);
        }, 600);
      }

      // ===== SAFETY: pre-flight delete count =====
      // Conta quantos deletes ESSE diff vai disparar antes de executar.
      // Se passar do limite, ABORTA esse workspace nesse ciclo — preserva
      // estado anterior em prevRef pra próxima sync re-comparar.
      // Why: real user delete = 1 item por interação. >3 numa cycle = bug/race.
      // How: usuário pode apagar até 3 lançamentos em sequência rápida e
      //      ainda passa; bulk-wipe (intencional ou bug) é bloqueado.
      const prevTxIds = new Set((pw.transactions || []).map(x => x.id));
      const currTxIds = new Set((cw.transactions || []).map(x => x.id));
      const prevReIds = new Set((pw.receitas || []).map(x => x.id));
      const currReIds = new Set((cw.receitas || []).map(x => x.id));
      let pendingDeletes = 0;
      for (const id of prevTxIds) if (!currTxIds.has(id)) pendingDeletes++;
      for (const id of prevReIds) if (!currReIds.has(id)) pendingDeletes++;

      if (pendingDeletes > 3) {
        console.error(`[sync] ABORTADO: ${pendingDeletes} deletes detectados em 1 ciclo para workspace "${wsKey}" — provável race condition. prev.transactions=${(pw.transactions||[]).length} curr.transactions=${(cw.transactions||[]).length} prev.receitas=${(pw.receitas||[]).length} curr.receitas=${(cw.receitas||[]).length}`);
        console.trace();
        if (window.toast) {
          window.toast({
            message: `🛑 Sync abortada (${pendingDeletes} exclusões em uma rodada). Recarregue a página.`,
            duration: 30000,
          });
        }
        // NÃO atualiza prevRef pra esse workspace — segura no estado anterior
        // pra próxima sync re-comparar (caso o estado já tenha estabilizado).
        continue;
      }

      // SEMPRE diff item-a-item — NUNCA bulk-delete pela sync.
      // Causa-raiz do incidente 2026-06-18: o atalho N→0 = deleteAll
      // disparava wipe da workspace inteira quando o array local zerava por
      // race (troca de workspace, refetch parcial, init, import re-render parcial).
      // Se precisar limpar tudo, chama db.deleteAllX direto no handler com
      // token explícito — nunca por este caminho.
      diffArray(pw.transactions || [], cw.transactions || [],
        (items) => window.db.insertTransactions(wsKey, items),
        (id)    => window.db.deleteTransaction(id),
        (id, t) => window.db.updateTransaction(id, t));
      diffArray(pw.receitas || [], cw.receitas || [],
        (items) => window.db.insertIncomes(wsKey, items),
        (id)    => window.db.deleteIncome(id),
        (id, r) => window.db.updateIncome(id, r));
    }
    prevRef.current = curr;
  }, [workspaces, loaded]);

  return { loaded, error };
}

// Main App shell - sidebar + topbar + tab switching
function App({ user }) {
  const tweaks = useTweaks({
    theme: "light",
    density: "comfortable",
    accentMode: "default",
    sidebarCollapsed: false,
  });

  // Sistema de Toast global — window.toast({ message, action: {label, onClick}, duration })
  // Cada ação reversível mostra um toast com "desfazer". Não bloqueia UI.
  const [toasts, setToasts] = React.useState([]);
  React.useEffect(() => {
    window.toast = (params) => {
      const id = Math.random().toString(36).slice(2);
      const t = { id, kind: "info", duration: 6000, ...params };
      setToasts(prev => [...prev, t]);
      setTimeout(() => setToasts(prev => prev.filter(x => x.id !== id)), t.duration);
      return id;
    };
    window.toast.dismiss = (id) => setToasts(prev => prev.filter(x => x.id !== id));
  }, []);

  // Pausa animações infinitas quando aba não tem foco (economia de CPU/bateria)
  React.useEffect(() => {
    const onVis = () => {
      if (document.hidden) document.body.classList.add("tab-hidden");
      else document.body.classList.remove("tab-hidden");
    };
    document.addEventListener("visibilitychange", onVis);
    return () => document.removeEventListener("visibilitychange", onVis);
  }, []);

  // Plano (free | pro) — persistido em Supabase (profiles.plan via webhook Stripe)
  const planHook = window.PlanilhaPlan.usePlan(user.id);
  const [upgradeModal, setUpgradeModal] = React.useState({ open: false, reason: "" });
  const showUpgrade = React.useCallback((reason) => setUpgradeModal({ open: true, reason: reason || "" }), []);
  const [stripeBanner, setStripeBanner] = React.useState(null); // { kind: "success"|"cancel", text }

  // Handler de retorno do Stripe Checkout (?stripe_success=1 ou ?stripe_cancel=1)
  React.useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const ok = params.get("stripe_success") === "1";
    const cancel = params.get("stripe_cancel") === "1";
    if (!ok && !cancel) return;

    if (ok) {
      setStripeBanner({ kind: "success", text: "✓ Pagamento confirmado! Ativando seu Pro… (pode levar alguns segundos)" });
      // Webhook do Stripe atualiza profiles.plan — damos refetch a cada 2s por até 20s
      let attempts = 0;
      const tick = async () => {
        attempts++;
        try {
          await planHook.refresh();
          const result = await window.db.getPlan();
          if (result?.plan === "pro") {
            setStripeBanner({ kind: "success", text: "✓ Pro ativado! Aproveite — todos os recursos liberados." });
            setTimeout(() => setStripeBanner(null), 6000);
            return;
          }
        } catch (e) {}
        if (attempts < 10) setTimeout(tick, 2000);
        else setStripeBanner({ kind: "success", text: "Pagamento confirmado, mas o Pro ainda não apareceu. Recarregue a página em alguns segundos." });
      };
      tick();
    } else if (cancel) {
      setStripeBanner({ kind: "cancel", text: "Pagamento cancelado. Você continua no Free — pode tentar novamente quando quiser." });
      setTimeout(() => setStripeBanner(null), 6000);
    }

    // Limpa os params da URL pra não disparar de novo num refresh
    const url = new URL(window.location.href);
    url.searchParams.delete("stripe_success");
    url.searchParams.delete("stripe_cancel");
    window.history.replaceState({}, "", url.toString());
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // Workspaces carregadas do Supabase
  const [workspaces, setWorkspaces] = React.useState(null);
  const [profile, setProfile] = React.useState(null);
  const { loaded, error: syncError } = useSupabaseSync(workspaces, setWorkspaces);

  React.useEffect(() => { window.db.fetchProfile().then(setProfile); }, []);

  // Estado da sessão persistido em localStorage — namespaced por usuário pra não vazar
  const SESSION_KEY = `fin_session_${user.id}`;
  const persisted = React.useMemo(() => {
    try { const raw = localStorage.getItem(SESSION_KEY); return raw ? JSON.parse(raw) : null; }
    catch (e) { return null; }
  }, [user.id]);

  const [activeWs, setActiveWs] = React.useState(persisted?.activeWs || null);
  const [tab, setTab] = React.useState(persisted?.tab || "dashboard");
  const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);

  // Toggle classe no body pra CSS aplicar drawer overlay
  React.useEffect(() => {
    if (mobileMenuOpen) document.body.classList.add("sidebar-open");
    else document.body.classList.remove("sidebar-open");
    return () => document.body.classList.remove("sidebar-open");
  }, [mobileMenuOpen]);

  // Fecha drawer ao trocar de tab OU de workspace (mobile)
  React.useEffect(() => { setMobileMenuOpen(false); }, [tab]);
  React.useEffect(() => { setMobileMenuOpen(false); }, [activeWs]);

  // ESC fecha drawer
  React.useEffect(() => {
    if (!mobileMenuOpen) return;
    const onKey = (e) => { if (e.key === "Escape") setMobileMenuOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [mobileMenuOpen]);

  const [currentMonth, setCurrentMonth] = React.useState(() => {
    // Default: mês atual de verdade (não hardcoded).
    // Persisted: usa apenas se for relativamente recente (até 1 mês atrás).
    // Se persisted estiver muito no passado (esquecido em sessão antiga ou
    // hardcoded de dev), pula pra mês atual real — evita gráficos vazios
    // por ver período antigo onde não tem dados novos.
    const now = new Date();
    const today = { year: now.getFullYear(), month: now.getMonth() };
    if (persisted?.currentMonth) {
      const p = persisted.currentMonth;
      const diffMonths = (today.year - p.year) * 12 + (today.month - p.month);
      // Aceita persisted entre 1 mês no futuro e 1 mês no passado
      if (diffMonths >= -1 && diffMonths <= 1) return p;
    }
    return today;
  });
  const [rangeMode, setRangeMode] = React.useState(persisted?.rangeMode || "MES");
  const [customRange, setCustomRange] = React.useState(() => {
    if (persisted?.customRange) return persisted.customRange;
    const d = new Date();
    return {
      from: new Date(d.getFullYear(), d.getMonth(), 1).toISOString().slice(0, 10),
      to:   new Date(d.getFullYear(), d.getMonth() + 1, 0).toISOString().slice(0, 10),
    };
  });

  React.useEffect(() => {
    document.documentElement.dataset.theme = tweaks.theme;
    document.documentElement.dataset.density = tweaks.density;
  }, [tweaks.theme, tweaks.density]);

  // Persiste qualquer mudança de sessão
  React.useEffect(() => {
    try {
      localStorage.setItem(SESSION_KEY, JSON.stringify({ activeWs, tab, currentMonth, rangeMode, customRange }));
    } catch (e) {}
  }, [activeWs, tab, currentMonth, rangeMode, customRange]);

  // Resolve workspace válida (precisa estar antes do early return — Rules of Hooks)
  const wsKeys = workspaces ? Object.keys(workspaces) : [];
  const activeKey = (workspaces && activeWs && workspaces[activeWs]) ? activeWs : wsKeys[0];

  // Garante que activeWs reflita uma chave válida (corrige sessão stale após delete)
  React.useEffect(() => {
    if (activeKey && activeWs !== activeKey) setActiveWs(activeKey);
  }, [activeKey, activeWs]);

  // Estado pra modal de criar conta
  const [createOpen, setCreateOpen] = React.useState(false);

  if (!loaded || !workspaces) {
    // Skeleton da app real — sidebar + topbar + dashboard com formas/blocos
    // animados. Sensação de "já carregou" (perceived performance).
    return (
      <div className="app skeleton-shell" style={{ display: "grid", gridTemplateColumns: "240px 1fr", minHeight: "100vh" }}>
        <aside style={{ background: "var(--surface-1)", borderRight: "1px solid var(--border)", padding: 18, display: "flex", flexDirection: "column", gap: 14 }}>
          <div className="skel" style={{ height: 32, width: "70%", borderRadius: 8 }} />
          <div className="skel" style={{ height: 1, background: "var(--border)" }} />
          <div className="skel" style={{ height: 12, width: "40%", borderRadius: 4 }} />
          {[1,2,3].map(i => <div key={i} className="skel" style={{ height: 36, borderRadius: 10 }} />)}
          <div className="skel" style={{ height: 12, width: "40%", borderRadius: 4, marginTop: 10 }} />
          {[1,2,3,4].map(i => <div key={i} className="skel" style={{ height: 32, borderRadius: 10 }} />)}
        </aside>
        <main style={{ display: "flex", flexDirection: "column" }}>
          <header style={{ padding: "18px 28px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              <div className="skel" style={{ height: 12, width: 180, borderRadius: 4 }} />
              <div className="skel" style={{ height: 32, width: 240, borderRadius: 8 }} />
            </div>
            <div className="skel" style={{ height: 36, width: 200, borderRadius: 999 }} />
          </header>
          <div style={{ padding: "24px 28px", display: "flex", flexDirection: "column", gap: 14 }}>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14 }}>
              {[1,2,3,4].map(i => <div key={i} className="skel" style={{ height: 110, borderRadius: 18 }} />)}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "auto minmax(280px, 1.1fr) minmax(220px, 1fr)", gap: 14 }}>
              <div className="skel" style={{ height: 280, width: 280, borderRadius: 18 }} />
              <div className="skel" style={{ height: 280, borderRadius: 18 }} />
              <div className="skel" style={{ height: 280, borderRadius: 18 }} />
            </div>
          </div>
        </main>
      </div>
    );
  }

  // Modo "chat-only" — URL com ?chat ativa lançamento rápido em tela cheia (mobile-friendly)
  const chatOnly = new URLSearchParams(window.location.search).has("chat");

  // "Phantom" workspace — quando usuário ainda não criou nenhuma conta. Permite navegar o app vazio.
  const phantomWs = {
    name: "Sem conta",
    fullName: "Crie sua primeira conta para começar",
    type: "business",
    accent: "#94a3b8",
    icon: "briefcase",
    monthlyGoal: 0,
    categories: [],
    payments: ["Pix", "Boleto", "Cartão", "Dinheiro", "Transferência"],
    transactions: [],
    receitas: [],
  };

  const realWs = workspaces[activeKey];
  const hasWs = !!realWs;
  const ws = realWs || phantomWs;

  // Quando não há workspace real, qualquer setWs vira "abre modal de criar conta"
  const setWs = (updater) => {
    if (!hasWs) { setCreateOpen(true); return; }
    setWorkspaces(prev => ({
      ...prev,
      [activeKey]: typeof updater === "function" ? updater(prev[activeKey]) : updater
    }));
  };

  // Recarrega workspaces após criar uma nova conta
  const handleAccountCreated = async (newKey) => {
    const data = await window.db.fetchAll();
    setWorkspaces(data || {});
    setActiveWs(newKey);
    setCreateOpen(false);
  };

  // Edita campos básicos de uma conta (nome, fullName, accent) sem precisar trocar pra ela
  const handleUpdateAccount = (key, patch) => {
    setWorkspaces(prev => ({
      ...prev,
      [key]: { ...prev[key], ...patch },
    }));
  };

  // Exclui uma conta (workspace) — cascata apaga lançamentos via FK no banco
  const handleDeleteAccount = async (keyToDelete) => {
    const target = workspaces[keyToDelete];
    if (!target) return;
    const txCount = (target.transactions || []).length + (target.receitas || []).length;
    const ok1 = confirm(
      `Excluir a conta "${target.name}"?\n\n` +
      (txCount > 0 ? `Isso vai apagar ${txCount} lançamento${txCount === 1 ? "" : "s"} também.\n\n` : "") +
      `Esta ação não pode ser desfeita.`
    );
    if (!ok1) return;
    const ok2 = confirm(`Tem certeza? Confirme a exclusão de "${target.name}".`);
    if (!ok2) return;

    const error = await window.db.deleteWorkspace(keyToDelete);
    if (error) { alert("Erro ao excluir: " + error.message); return; }

    // Atualiza estado local removendo a workspace deletada
    setWorkspaces(prev => {
      const next = { ...prev };
      delete next[keyToDelete];
      return next;
    });
    // Se era a ativa, troca pra primeira disponível
    if (activeWs === keyToDelete) {
      const remaining = Object.keys(workspaces).filter(k => k !== keyToDelete);
      setActiveWs(remaining[0] || null);
    }
  };

  const accent = ws.accent;

  // Modo chat-only: tela cheia, sem sidebar/topbar — usado pra acesso mobile via link
  if (chatOnly && hasWs) {
    return <ChatOnlyView ws={ws} setWs={setWs} accent={accent} workspaces={workspaces} activeKey={activeKey} setActiveWs={setActiveWs} user={user} isPro={planHook.isPro} showUpgrade={showUpgrade} />;
  }

  return (
    <div className="app" style={{ "--accent": accent }}>
      {mobileMenuOpen && (
        <div className="sidebar-backdrop" onClick={() => setMobileMenuOpen(false)} />
      )}
      <Sidebar
        workspaces={workspaces}
        activeWs={activeWs}
        setActiveWs={setActiveWs}
        tab={tab}
        setTab={setTab}
        collapsed={tweaks.sidebarCollapsed}
        toggleCollapsed={() => tweaks.set("sidebarCollapsed", !tweaks.sidebarCollapsed)}
        theme={tweaks.theme}
        toggleTheme={() => tweaks.set("theme", tweaks.theme === "dark" ? "light" : "dark")}
        user={user}
        profile={profile}
        onCreateAccount={() => {
          // Free: limite de 1 workspace
          if (!planHook.isPro && Object.keys(workspaces).length >= window.PlanilhaPlan.FREE_LIMITS.workspaces) {
            showUpgrade(`Plano Free permite só 1 conta. No Pro você cria quantas quiser (PF + PJ + holdings).`);
            return;
          }
          setCreateOpen(true);
        }}
        onDeleteAccount={handleDeleteAccount}
        onUpdateAccount={handleUpdateAccount}
        plan={planHook.plan}
        showUpgrade={showUpgrade}
        closeMobileMenu={() => setMobileMenuOpen(false)}
      />

      <main className="main">
        <Topbar
          ws={ws}
          tab={tab}
          currentMonth={currentMonth}
          setCurrentMonth={setCurrentMonth}
          accent={accent}
          onHamburger={() => setMobileMenuOpen(true)}
        />

        <div className="content">
          {stripeBanner && <StripeBanner banner={stripeBanner} onClose={() => setStripeBanner(null)} />}
          {!hasWs && <NoAccountBanner onCreate={() => setCreateOpen(true)} />}
          {tab === "dashboard" && <Dashboard ws={ws} setWs={setWs} activeWs={activeWs} accent={accent} currentMonth={currentMonth} setCurrentMonth={setCurrentMonth} rangeMode={rangeMode} setRangeMode={setRangeMode} customRange={customRange} setCustomRange={setCustomRange} isPro={planHook.isPro} showUpgrade={showUpgrade} />}
          {tab === "transactions" && <Transactions ws={ws} setWs={setWs} activeWs={activeWs} accent={accent} currentMonth={currentMonth} setCurrentMonth={setCurrentMonth} rangeMode={rangeMode} setRangeMode={setRangeMode} customRange={customRange} setCustomRange={setCustomRange} isPro={planHook.isPro} showUpgrade={showUpgrade} />}
          {tab === "reports" && <Reports key={activeKey || "phantom"} ws={ws} accent={accent} currentMonth={currentMonth} isPro={planHook.isPro} showUpgrade={showUpgrade} />}
          {tab === "settings" && <Settings ws={ws} setWs={setWs} activeWs={activeKey} setWorkspaces={setWorkspaces} accent={accent} setRangeMode={setRangeMode} setCustomRange={setCustomRange} plan={planHook.plan} setPlan={planHook.setPlan} showUpgrade={showUpgrade} userId={user.id} />}
        </div>
      </main>

      {createOpen && <CreateAccountModal onClose={() => setCreateOpen(false)} onCreated={handleAccountCreated} />}

      {/* Chat flutuante de lançamento rápido — só com workspace real */}
      {hasWs && <QuickEntryChat ws={ws} setWs={setWs} accent={accent} isPro={planHook.isPro} showUpgrade={showUpgrade} userId={user.id} />}

      {/* Modal global de upgrade Pro */}
      <window.PlanilhaPlan.UpgradeModal
        open={upgradeModal.open}
        accent={accent}
        reason={upgradeModal.reason}
        onClose={() => setUpgradeModal({ open: false, reason: "" })}
      />

      {/* Toast container — toasts globais com undo */}
      <ToastContainer toasts={toasts} onDismiss={(id) => setToasts(prev => prev.filter(t => t.id !== id))} />
    </div>
  );
}

// Toast container — fixed bottom-right, stack vertical, click outside dismiss
function ToastContainer({ toasts, onDismiss }) {
  if (!toasts || toasts.length === 0) return null;
  return (
    <div className="toast-stack" style={{
      position: "fixed", bottom: 20, right: 20, zIndex: 10000,
      display: "flex", flexDirection: "column", gap: 8,
      pointerEvents: "none",
    }}>
      {toasts.map(t => (
        <div key={t.id} className="toast-item" style={{
          background: "var(--surface-1)",
          border: "1px solid var(--border)",
          boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
          padding: "12px 16px",
          borderRadius: 12,
          display: "flex", alignItems: "center", gap: 12,
          fontSize: 13.5, color: "var(--fg-1)",
          minWidth: 260, maxWidth: 380,
          pointerEvents: "auto",
          animation: "toastIn .2s ease",
        }}>
          <span style={{ flex: 1 }}>{t.message}</span>
          {t.action && (
            <button
              onClick={() => { t.action.onClick(); onDismiss(t.id); }}
              style={{
                background: "transparent", border: "none",
                color: "var(--green)", fontWeight: 600,
                cursor: "pointer", fontSize: 13, fontFamily: "inherit",
                padding: "4px 8px", borderRadius: 6, whiteSpace: "nowrap",
              }}
            >
              {t.action.label}
            </button>
          )}
          <button
            onClick={() => onDismiss(t.id)}
            style={{
              background: "transparent", border: "none",
              color: "var(--fg-3)", cursor: "pointer", padding: 0,
              display: "flex", alignItems: "center", justifyContent: "center",
            }}
            aria-label="Fechar"
          >
            <Icon name="x" size={14} />
          </button>
        </div>
      ))}
    </div>
  );
}

// Modo chat-only — tela cheia pra mobile, sem sidebar/topbar
function ChatOnlyView({ ws, setWs, accent, workspaces, activeKey, setActiveWs, user, isPro, showUpgrade }) {
  const [signOutOpen, setSignOutOpen] = React.useState(false);
  const wsList = Object.entries(workspaces || {}).map(([k, v]) => ({ key: k, name: v.name, icon: v.icon, accent: v.accent, type: v.type }));

  // Trava viewport modo app: sem zoom, sem pull-to-refresh, classe no body
  // pra CSS aplicar overscroll-behavior, position fixed, etc.
  React.useEffect(() => {
    document.body.classList.add("chat-only");
    document.documentElement.classList.add("chat-only");
    const meta = document.getElementById("viewport-meta");
    const original = meta?.getAttribute("content");
    if (meta) {
      meta.setAttribute(
        "content",
        "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover"
      );
    }

    // visualViewport API: --vvh = altura visível REAL (descontando URL bar
    // do Safari iOS, teclado virtual quando aberto, etc). Atualiza em resize
    // (browser UI aparecendo/sumindo, teclado abrindo).
    const updateVvh = () => {
      const h = window.visualViewport?.height || window.innerHeight;
      document.documentElement.style.setProperty("--vvh", `${h}px`);
    };
    updateVvh();
    window.visualViewport?.addEventListener("resize", updateVvh);
    window.addEventListener("resize", updateVvh);
    window.addEventListener("orientationchange", updateVvh);

    return () => {
      document.body.classList.remove("chat-only");
      document.documentElement.classList.remove("chat-only");
      if (meta && original) meta.setAttribute("content", original);
      window.visualViewport?.removeEventListener("resize", updateVvh);
      window.removeEventListener("resize", updateVvh);
      window.removeEventListener("orientationchange", updateVvh);
      document.documentElement.style.removeProperty("--vvh");
    };
  }, []);

  return (
    <div className="chat-only-shell" style={{ display: "flex", flexDirection: "column", background: "var(--bg)", "--accent": accent }}>
      {/* Header compacto: conta atual + trocar */}
      <header style={{ padding: "12px 16px", borderBottom: "1px solid var(--border)", background: "var(--surface-1)", display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
        <span style={{ width: 36, height: 36, borderRadius: 10, background: `color-mix(in oklab, ${accent} 14%, transparent)`, color: accent, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
          <Icon name={ws.icon || (ws.type === "personal" ? "person" : "briefcase")} size={18} />
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 10.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5 }}>Lançando em</div>
          <select
            value={activeKey || ""}
            onChange={e => setActiveWs(e.target.value)}
            style={{
              fontSize: 14, fontWeight: 600, color: "var(--fg-1)",
              border: "none", background: "transparent", padding: 0, fontFamily: "inherit", cursor: "pointer", maxWidth: "100%",
            }}
          >
            {wsList.map(w => <option key={w.key} value={w.key}>{w.name}</option>)}
          </select>
        </div>
        <button
          onClick={() => setSignOutOpen(o => !o)}
          className="icon-btn"
          title="Conta"
          style={{ width: 36, height: 36 }}
        >
          <Icon name="person" size={16} />
        </button>
      </header>

      {/* Menu flutuante: sair */}
      {signOutOpen && (
        <>
          <div onClick={() => setSignOutOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 50 }} />
          <div style={{ position: "absolute", top: 60, right: 12, zIndex: 60, background: "var(--surface-1)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "0 6px 24px rgba(0,0,0,0.12)", padding: 6, minWidth: 200 }}>
            <div style={{ padding: "8px 10px", borderBottom: "1px solid var(--border)", fontSize: 11.5, color: "var(--fg-3)" }}>{user?.email || "—"}</div>
            <button
              onClick={async () => { await window.db.auth.signOut(); window.location.href = "index.html"; }}
              className="menu-item"
              style={{ color: "var(--danger)" }}
            >
              <Icon name="x" size={11} /> Sair
            </button>
            <button
              onClick={async () => {
                // Mudar do modo chat (limitado) pro app completo exige re-auth
                // por segurança — se alguém pega o celular já logado no chat,
                // não acessa dados financeiros completos sem provar identidade.
                const target = window.location.pathname; // /Financeiro (sem ?chat)
                await window.db.auth.signOut();
                window.location.href = target;
              }}
              className="menu-item"
              style={{ width: "100%", textAlign: "left" }}
            >
              <Icon name="briefcase" size={11} /> Abrir app completo
            </button>
          </div>
        </>
      )}

      {/* Chat ocupa o resto da tela */}
      <div style={{ flex: 1, position: "relative", overflow: "hidden" }}>
        <QuickEntryChat ws={ws} setWs={setWs} accent={accent} embedded isPro={isPro} showUpgrade={showUpgrade} userId={user?.id} />
      </div>
    </div>
  );
}

// Banner mostrado quando usuário ainda não criou conta
function StripeBanner({ banner, onClose }) {
  const isSuccess = banner.kind === "success";
  return (
    <div style={{
      marginBottom: 16, padding: "12px 16px",
      background: isSuccess
        ? "color-mix(in oklab, var(--success, #16a34a) 10%, var(--surface-1))"
        : "color-mix(in oklab, var(--warn) 8%, var(--surface-1))",
      border: `1px solid color-mix(in oklab, ${isSuccess ? "var(--success, #16a34a)" : "var(--warn)"} 30%, transparent)`,
      borderRadius: 12,
      display: "flex", alignItems: "center", gap: 12,
      animation: "fadeIn .3s ease",
    }}>
      <div style={{ flex: 1, fontSize: 13.5, color: "var(--fg-1)", lineHeight: 1.5 }}>{banner.text}</div>
      <button onClick={onClose} className="icon-btn" title="Fechar"><Icon name="x" size={14} /></button>
    </div>
  );
}

function NoAccountBanner({ onCreate }) {
  return (
    <div style={{ marginBottom: 16, padding: "16px 20px", background: "color-mix(in oklab, var(--warn) 8%, var(--surface-1))", border: "1px solid color-mix(in oklab, var(--warn) 25%, transparent)", borderRadius: 12, display: "flex", alignItems: "center", gap: 14 }}>
      <div style={{ width: 36, height: 36, borderRadius: 10, background: "color-mix(in oklab, var(--warn) 18%, transparent)", color: "var(--warn)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
        <Icon name="alert" size={18} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-1)" }}>Você ainda não criou nenhuma conta</div>
        <div style={{ fontSize: 12.5, color: "var(--fg-2)", marginTop: 2 }}>Crie uma conta empresarial ou pessoal pra começar a registrar lançamentos.</div>
      </div>
      <button className="btn-primary" onClick={onCreate} style={{ background: "var(--warn)", flexShrink: 0 }}>
        <Icon name="plus" size={13} /> Criar conta
      </button>
    </div>
  );
}

function Sidebar({ workspaces, activeWs, setActiveWs, tab, setTab, collapsed, toggleCollapsed, theme, toggleTheme, user, profile, onCreateAccount, onDeleteAccount, onUpdateAccount, plan, showUpgrade, closeMobileMenu }) {
  const isPro = plan === "pro";
  const [pickerOpen, setPickerOpen] = React.useState(false);
  const [userMenuOpen, setUserMenuOpen] = React.useState(false);
  // Lista dinâmica das workspaces do usuário (em vez de hardcoded)
  const wsList = Object.entries(workspaces).map(([key, w]) => ({ key, ...w }));
  const active = workspaces[activeWs] || wsList[0];
  const hasAccounts = wsList.length > 0;
  const tabs = [
    { key: "dashboard", label: "Visão geral", icon: "dashboard" },
    { key: "transactions", label: "Transações", icon: "list" },
    { key: "reports", label: "Relatórios", icon: "chart" },
    { key: "settings", label: "Configurações", icon: "settings" },
  ];

  return (
    <aside className={"sidebar" + (collapsed ? " collapsed" : "")}>
      <div className="sidebar-brand">
        <div className="brand-mark">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
            <rect x="3" y="3" width="8" height="8" rx="2" fill="var(--accent)" />
            <rect x="13" y="3" width="8" height="8" rx="2" fill="currentColor" opacity="0.5" />
            <rect x="3" y="13" width="8" height="8" rx="2" fill="currentColor" opacity="0.3" />
            <rect x="13" y="13" width="8" height="8" rx="2" fill="var(--accent)" opacity="0.7" />
          </svg>
        </div>
        {!collapsed && (
          <div>
            <div style={{ fontFamily: "'Fraunces', Georgia, serif", fontSize: 16, fontWeight: 400, color: "var(--fg-1)", letterSpacing: "-0.02em", lineHeight: 1 }}>Planilha IA</div>
            <div className="eyebrow" style={{ marginTop: 3, fontSize: 9.5 }}>A planilha com cérebro</div>
          </div>
        )}
      </div>

      <div className="sidebar-section">
        {!collapsed && <div className="sidebar-label">Conta</div>}
        {hasAccounts ? (
          <button
            className="ws-btn active"
            onClick={() => { setPickerOpen(true); closeMobileMenu?.(); }}
            style={{ "--ws-accent": active.accent }}
            title={collapsed ? `${active.name} — trocar` : "Trocar de perfil"}
          >
            <span className="ws-icon" style={{ background: `color-mix(in oklab, ${active.accent} 15%, transparent)`, color: active.accent, overflow: "hidden" }}>
              {active.logo
                ? <img src={active.logo} style={{ width: 32, height: 32, objectFit: "cover" }} />
                : <Icon name={active.icon} size={16} />}
            </span>
            {!collapsed && (
              <div style={{ flex: 1, textAlign: "left", minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-1)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{active.name}</div>
                <div style={{ fontSize: 10.5, color: "var(--fg-3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{active.fullName}</div>
              </div>
            )}
            {!collapsed && (
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: "var(--fg-3)", flexShrink: 0 }}>
                <polyline points="7 15 12 20 17 15"/>
                <polyline points="7 9 12 4 17 9"/>
              </svg>
            )}
          </button>
        ) : (
          <button
            className="ws-btn"
            onClick={onCreateAccount}
            style={{ "--ws-accent": "var(--warn)", border: "1px dashed color-mix(in oklab, var(--warn) 50%, var(--border))" }}
            title="Criar primeira conta"
          >
            <span className="ws-icon" style={{ background: "color-mix(in oklab, var(--warn) 15%, transparent)", color: "var(--warn)" }}>
              <Icon name="plus" size={16} />
            </span>
            {!collapsed && (
              <div style={{ flex: 1, textAlign: "left", minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-1)" }}>Criar conta</div>
                <div style={{ fontSize: 10.5, color: "var(--fg-3)" }}>Empresarial ou pessoal</div>
              </div>
            )}
          </button>
        )}
      </div>

      {pickerOpen && (
        <ProfilePicker
          wsList={wsList}
          activeWs={activeWs}
          onPick={(k) => { setActiveWs(k); setPickerOpen(false); }}
          onClose={() => setPickerOpen(false)}
          onCreate={() => { setPickerOpen(false); onCreateAccount(); }}
          onDelete={onDeleteAccount}
          onUpdate={onUpdateAccount}
        />
      )}

      <div className="sidebar-section">
        {!collapsed && <div className="sidebar-label">Navegação</div>}
        {tabs.map(t => (
          <button
            key={t.key}
            className={"nav-btn" + (tab === t.key ? " active" : "")}
            onClick={() => setTab(t.key)}
            title={collapsed ? t.label : ""}
          >
            <Icon name={t.icon} size={17} />
            {!collapsed && <span>{t.label}</span>}
          </button>
        ))}
      </div>

      <div style={{ marginTop: "auto", display: "flex", flexDirection: "column", gap: 6 }}>
        <button className="nav-btn" onClick={toggleTheme} title="Tema">
          <Icon name={theme === "dark" ? "sun" : "moon"} size={16} />
          {!collapsed && <span>{theme === "dark" ? "Claro" : "Escuro"}</span>}
        </button>
        <button className="nav-btn sidebar-collapse-btn" onClick={toggleCollapsed} title={collapsed ? "Expandir" : "Recolher"}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            {collapsed ? <polyline points="9 18 15 12 9 6"/> : <polyline points="15 18 9 12 15 6"/>}
          </svg>
          {!collapsed && <span>Recolher</span>}
        </button>

        {/* Identidade do usuário + logout */}
        <div style={{ position: "relative", paddingTop: 8, marginTop: 4, borderTop: "1px solid var(--border)" }}>
          <button className="nav-btn" onClick={() => setUserMenuOpen(o => !o)} title={user?.email}>
            <span style={{ width: 24, height: 24, borderRadius: 6, background: "color-mix(in oklab, var(--accent) 15%, transparent)", color: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, flexShrink: 0 }}>
              {(profile?.full_name || user?.email || "?").slice(0, 1).toUpperCase()}
            </span>
            {!collapsed && (
              <span style={{ flex: 1, display: "flex", alignItems: "center", gap: 6, overflow: "hidden", minWidth: 0 }}>
                <span style={{ flex: 1, textAlign: "left", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontSize: 12 }}>
                  {profile?.full_name || user?.email?.split("@")[0]}
                </span>
                <span style={{
                  padding: "2px 7px", borderRadius: 99, fontSize: 9, fontWeight: 700, letterSpacing: "0.08em",
                  fontFamily: "'JetBrains Mono', monospace",
                  background: isPro ? "var(--green)" : "var(--surface-2)",
                  color: isPro ? "#06120c" : "var(--fg-3)",
                  border: isPro ? "none" : "1px solid var(--border)",
                  flexShrink: 0,
                }}>
                  {isPro ? "PRO" : "FREE"}
                </span>
              </span>
            )}
          </button>
          {userMenuOpen && (
            <div style={{ position: "absolute", bottom: "calc(100% + 6px)", left: 0, right: 0, background: "var(--surface-1)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "var(--shadow-md)", padding: 6, zIndex: 100 }}>
              <div style={{ padding: "8px 10px", fontSize: 11, color: "var(--fg-3)", borderBottom: "1px solid var(--border)", marginBottom: 4 }}>
                {user?.email}
                <div style={{ marginTop: 2, fontSize: 10, color: isPro ? "var(--green)" : "var(--fg-3)", fontWeight: 600, fontFamily: "'JetBrains Mono', monospace", letterSpacing: "0.08em" }}>
                  PLANO {isPro ? "PRO" : "GRATUITO"}
                </div>
              </div>
              {!isPro && (
                <button className="nav-btn" style={{ width: "100%", color: "var(--green)", fontWeight: 600 }} onClick={() => { setUserMenuOpen(false); showUpgrade && showUpgrade(); }}>
                  <Icon name="spark" size={14} />
                  <span>Fazer upgrade pro Pro</span>
                </button>
              )}
              <button className="nav-btn" style={{ width: "100%", color: "var(--fg-2)" }} onClick={() => { setUserMenuOpen(false); setTab("settings"); }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <circle cx="12" cy="12" r="3"/>
                  <path d="M12 1v6m0 6v6M4.22 4.22l4.24 4.24m7.08 7.08l4.24 4.24M1 12h6m6 0h6M4.22 19.78l4.24-4.24m7.08-7.08l4.24-4.24"/>
                </svg>
                <span>Gerenciar plano</span>
              </button>
              <button className="nav-btn" style={{ width: "100%", color: "var(--danger)" }} onClick={async () => { await window.db.auth.signOut(); window.location.href = "index.html"; }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
                  <polyline points="16 17 21 12 16 7"/>
                  <line x1="21" y1="12" x2="9" y2="12"/>
                </svg>
                <span>Sair</span>
              </button>
            </div>
          )}
        </div>
      </div>
    </aside>
  );
}

function ProfilePicker({ wsList, activeWs, onPick, onClose, onCreate, onDelete, onUpdate }) {
  const [editing, setEditing] = React.useState(null); // workspace sendo editada
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape" && !editing) onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose, editing]);

  // Portal pro body — escapa o "containing block" da Sidebar (transform:translateX)
  // que estava limitando o position:fixed do backdrop a só 320px de largura.
  return ReactDOM.createPortal(
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal profile-picker" onClick={(e) => e.stopPropagation()}>
        <div className="profile-picker-header" style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 16, gap: 12 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: 1, textTransform: "uppercase", color: "var(--fg-3)", marginBottom: 4 }}>Trocar de perfil</div>
            <div style={{ fontSize: 18, fontWeight: 600, color: "var(--fg-1)", letterSpacing: -0.3 }}>Selecione uma conta</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Fechar" style={{ flexShrink: 0 }}>
            <Icon name="x" size={16} />
          </button>
        </div>
        <div className="profile-picker-grid" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {wsList.map(w => {
            const isActive = activeWs === w.key;
            const txCount = (w.transactions || []).length;
            return (
              <div key={w.key} className="profile-card-wrap" style={{ position: "relative" }}>
                <button
                  onClick={() => onPick(w.key)}
                  className="profile-card"
                  style={{
                    "--ws-accent": w.accent,
                    border: isActive ? `1.5px solid ${w.accent}` : "1px solid var(--border)",
                    background: isActive ? `color-mix(in oklab, ${w.accent} 6%, var(--bg-1))` : "var(--bg-1)",
                    width: "100%",
                  }}
                >
                  <div className="profile-card-header" style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
                    <span className="ws-icon" style={{ background: `color-mix(in oklab, ${w.accent} 15%, transparent)`, color: w.accent, width: 36, height: 36, overflow: "hidden", flexShrink: 0 }}>
                      {w.logo
                        ? <img src={w.logo} style={{ width: 36, height: 36, objectFit: "cover" }} />
                        : <Icon name={w.icon} size={18} />}
                    </span>
                    <div className="profile-card-info" style={{ display: "none", flex: 1, minWidth: 0, textAlign: "left" }}>
                      <div style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-1)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{w.name}</div>
                      <div style={{ fontSize: 11, color: "var(--fg-3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{w.fullName}</div>
                    </div>
                    {isActive && (
                      <span className="profile-active-badge" style={{ marginLeft: "auto", fontSize: 10, fontWeight: 600, letterSpacing: 0.6, textTransform: "uppercase", color: w.accent, background: `color-mix(in oklab, ${w.accent} 12%, transparent)`, padding: "3px 8px", borderRadius: 4, flexShrink: 0 }}>
                        Atual
                      </span>
                    )}
                  </div>
                  <div className="profile-card-name" style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-1)", marginBottom: 2, textAlign: "left" }}>{w.name}</div>
                  <div className="profile-card-fullname" style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 10, textAlign: "left" }}>{w.fullName}</div>
                  <div className="profile-card-count" style={{ fontSize: 10.5, color: "var(--fg-3)", textAlign: "left" }}>
                    {txCount === 0 ? "Sem lançamentos ainda" : `${txCount} lançamento${txCount === 1 ? "" : "s"}`}
                  </div>
                </button>
                {/* Botão de editar — canto inferior direito, ao lado da lixeira */}
                {onUpdate && (
                  <button
                    onClick={(e) => { e.stopPropagation(); setEditing(w); }}
                    title="Editar conta"
                    className="profile-edit-btn"
                    style={{
                      position: "absolute", bottom: 8, right: 42, width: 26, height: 26,
                      borderRadius: 6, border: "none", cursor: "pointer",
                      background: "var(--surface-2)",
                      color: "var(--fg-2)", display: "flex", alignItems: "center", justifyContent: "center",
                      fontFamily: "inherit", padding: 0,
                    }}
                  >
                    <Icon name="edit" size={13} />
                  </button>
                )}
                {/* Botão de excluir (canto inferior direito do card — fica longe do badge "Atual") */}
                {onDelete && (
                  <button
                    onClick={(e) => { e.stopPropagation(); onDelete(w.key); }}
                    title="Excluir conta"
                    className="profile-delete-btn"
                    style={{
                      position: "absolute", bottom: 8, right: 8, width: 26, height: 26,
                      borderRadius: 6, border: "none", cursor: "pointer",
                      background: "color-mix(in oklab, var(--danger) 8%, transparent)",
                      color: "var(--danger)", display: "flex", alignItems: "center", justifyContent: "center",
                      fontFamily: "inherit", padding: 0,
                    }}
                  >
                    <Icon name="trash" size={13} />
                  </button>
                )}
              </div>
            );
          })}

          {/* Card "+ Nova conta" */}
          {onCreate && (
            <button
              onClick={onCreate}
              className="profile-card profile-card-new"
              style={{
                border: "1.5px dashed var(--border-strong)",
                background: "transparent",
                display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
                minHeight: 120, gap: 8, cursor: "pointer", fontFamily: "inherit",
              }}
            >
              <div style={{ width: 36, height: 36, borderRadius: 10, background: "var(--surface-2)", color: "var(--fg-2)", display: "flex", alignItems: "center", justifyContent: "center" }}>
                <Icon name="plus" size={18} />
              </div>
              <div style={{ fontSize: 13, fontWeight: 600, color: "var(--fg-1)" }}>Nova conta</div>
              <div style={{ fontSize: 11, color: "var(--fg-3)" }}>Empresarial ou pessoal</div>
            </button>
          )}
        </div>
      </div>

      {editing && (
        <EditAccountModal
          ws={editing}
          onClose={() => setEditing(null)}
          onSave={(patch) => { onUpdate(editing.key, patch); setEditing(null); }}
        />
      )}
    </div>,
    document.body
  );
}

// Modal de edição rápida de uma conta (nome, nome completo, cor)
function EditAccountModal({ ws, onClose, onSave }) {
  const [name, setName] = React.useState(ws.name || "");
  const [fullName, setFullName] = React.useState(ws.fullName || "");
  const [accent, setAccent] = React.useState(ws.accent || "#0f172a");

  React.useEffect(() => {
    const fn = e => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", fn);
    return () => window.removeEventListener("keydown", fn);
  }, [onClose]);

  const submit = () => {
    if (!name.trim()) return;
    onSave({ name: name.trim(), fullName: fullName.trim() || name.trim(), accent });
  };

  const isBusiness = ws.type !== "personal";
  const labels = isBusiness
    ? { name: "Nome fantasia", full: "Razão social (opcional)" }
    : { name: "Apelido da conta", full: "Nome completo (opcional)" };

  return (
    <div className="modal-backdrop" onClick={onClose} style={{ zIndex: 1000 }}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ width: 440, maxWidth: "calc(100vw - 32px)", padding: 24 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 18 }}>
          <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>Editar conta</h3>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16}/></button>
        </div>

        <div style={{ display: "grid", gap: 14 }}>
          <FormField label={labels.name} required>
            <input className="input" value={name} onChange={e => setName(e.target.value)} autoFocus style={{ width: "100%", boxSizing: "border-box" }} />
          </FormField>
          <FormField label={labels.full}>
            <input className="input" value={fullName} onChange={e => setFullName(e.target.value)} style={{ width: "100%", boxSizing: "border-box" }} />
          </FormField>
          <FormField label="Cor de destaque">
            <div style={{ display: "flex", gap: 8 }}>
              {["#0f172a", "#16a34a", "#b45309", "#7c3aed", "#0ea5e9", "#dc2626", "#0891b2"].map(c => (
                <button key={c} type="button" onClick={() => setAccent(c)}
                  style={{ width: 32, height: 32, borderRadius: 8, background: c,
                    border: accent === c ? "2px solid var(--fg-1)" : "1px solid var(--border)",
                    cursor: "pointer", padding: 0 }} />
              ))}
            </div>
          </FormField>
        </div>

        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 20 }}>
          <button className="btn-ghost" onClick={onClose}>Cancelar</button>
          <button className="btn-primary" onClick={submit} disabled={!name.trim()} style={{ opacity: !name.trim() ? 0.5 : 1 }}>
            Salvar alterações
          </button>
        </div>
      </div>
    </div>
  );
}

function Topbar({ ws, tab, currentMonth, setCurrentMonth, accent, onHamburger }) {
  const titles = {
    dashboard: <>Visão <em>geral</em></>,
    transactions: "Transações",
    reports: "Relatórios",
    settings: "Configurações"
  };
  const titlesPlain = {
    dashboard: "Visão geral",
    transactions: "Transações",
    reports: "Relatórios",
    settings: "Configurações"
  };
  const monthName = new Date(currentMonth.year, currentMonth.month, 1).toLocaleDateString("pt-BR", { month: "long", year: "numeric" });

  const shift = (delta) => {
    const d = new Date(currentMonth.year, currentMonth.month + delta, 1);
    setCurrentMonth({ year: d.getFullYear(), month: d.getMonth() });
  };

  return (
    <header className="topbar">
      {/* Hamburger — só visível em mobile via CSS */}
      <button
        className="hamburger-btn"
        onClick={onHamburger}
        title="Menu"
        aria-label="Abrir menu"
      >
        <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <line x1="3" y1="6" x2="21" y2="6" />
          <line x1="3" y1="12" x2="21" y2="12" />
          <line x1="3" y1="18" x2="21" y2="18" />
        </svg>
      </button>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="breadcrumb">
          <span>{ws.fullName}</span>
          <span style={{ color: "var(--fg-3)" }}>/</span>
          <span style={{ color: "var(--fg-3)" }}>{titlesPlain[tab]}</span>
        </div>
        <h1 className="page-title">{titles[tab]}</h1>
      </div>
      {(tab === "dashboard" || tab === "transactions") && (
        <div className="month-pager">
          <button className="icon-btn" onClick={() => shift(-1)}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polyline points="15 18 9 12 15 6"/></svg>
          </button>
          <span style={{ minWidth: 140, textAlign: "center", fontSize: 13, fontWeight: 500, color: "var(--fg-1)", textTransform: "capitalize" }}>{monthName}</span>
          <button className="icon-btn" onClick={() => shift(1)}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polyline points="9 18 15 12 9 6"/></svg>
          </button>
        </div>
      )}
    </header>
  );
}

// Tweaks: simple custom hook because we need to dispatch the host protocol too
function useTweaks(defaults) {
  const [state, setState] = React.useState(defaults);
  const set = (key, value) => {
    setState(prev => ({ ...prev, [key]: value }));
    try { window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [key]: value } }, "*"); } catch (e) {}
  };
  React.useEffect(() => {
    const onMsg = (e) => {
      if (!e.data) return;
      if (e.data.type === "__activate_edit_mode") setState(s => ({ ...s, _editOpen: true }));
      if (e.data.type === "__deactivate_edit_mode") setState(s => ({ ...s, _editOpen: false }));
    };
    window.addEventListener("message", onMsg);
    try { window.parent.postMessage({ type: "__edit_mode_available" }, "*"); } catch (e) {}
    return () => window.removeEventListener("message", onMsg);
  }, []);
  return { ...state, set };
}

// ---------- CreateAccountModal ----------
// Cria uma nova workspace (empresarial ou pessoal). Sem CNPJ obrigatório.
function CreateAccountModal({ onClose, onCreated }) {
  const [type, setType] = React.useState("business");
  const [name, setName] = React.useState("");
  const [fullName, setFullName] = React.useState("");      // razão social (empresa)
  const [members, setMembers] = React.useState("");        // membros da família (pessoal)
  const [monthlyGoal, setMonthlyGoal] = React.useState(""); // limite mensal (pessoal)
  const [accent, setAccent] = React.useState("#0f172a");
  const [loading, setLoading] = React.useState(false);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    const fn = e => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", fn);
    return () => window.removeEventListener("keydown", fn);
  }, [onClose]);

  const isBusiness = type === "business";

  const submit = async (e) => {
    e?.preventDefault();
    if (!name.trim()) { setErr(isBusiness ? "Informe o nome fantasia." : "Informe o apelido da conta."); return; }
    setLoading(true); setErr(null);
    // Membros viram a base do dropdown "who" nos lançamentos pessoais
    const memberList = isBusiness
      ? []
      : members.split(",").map(s => s.trim()).filter(Boolean);
    const goalNum = parseFloat(String(monthlyGoal).replace(",", ".")) || 0;

    const ws = {
      key: crypto.randomUUID().slice(0, 12),
      name: name.trim(),                                  // nome fantasia (empresa) | apelido (pessoal)
      fullName: isBusiness
        ? (fullName.trim() || name.trim())                // razão social
        : (memberList.length > 0 ? memberList.join(" · ") : name.trim()),
      accent,
      icon: isBusiness ? "briefcase" : "person",
      type,
      categories: isBusiness
        ? ["CUSTOS FIXOS", "CUSTOS VARIÁVEIS", "FOLHA", "TRIBUTOS", "TRANSPORTE", "MARKETING", "TECNOLOGIA", "OUTROS"]
        : ["MORADIA", "ALIMENTAÇÃO", "TRANSPORTE", "SAÚDE", "EDUCAÇÃO", "LAZER", "ASSINATURAS", "OUTROS"],
      incomeCategories: isBusiness
        ? ["VENDAS", "SERVIÇOS", "ALUGUÉIS", "RENDIMENTOS", "OUTROS"]
        : ["SALÁRIO", "FREELANCE", "RENDIMENTOS", "PRESENTE", "OUTROS"],
      payments: ["Pix", "Boleto", "Cartão", "Dinheiro", "Transferência"],
      monthlyGoal: isBusiness ? 0 : goalNum,
      _order: 0,
    };
    try {
      await window.db.createWorkspace(ws);
      await onCreated(ws.key);
    } catch (ex) {
      setErr("Erro ao criar conta: " + (ex?.message || ex));
      setLoading(false);
    }
  };

  const TypeCard = ({ k, l, d, icon }) => {
    const active = type === k;
    return (
      <button type="button" onClick={() => setType(k)} style={{
        textAlign: "left", padding: 14, cursor: "pointer", fontFamily: "inherit",
        border: active ? `2px solid ${accent}` : "1.5px solid var(--border)",
        borderRadius: 12,
        background: active ? `color-mix(in oklab, ${accent} 6%, var(--bg-1))` : "var(--bg-1)",
        transition: "all .12s",
      }}>
        <div style={{ width: 32, height: 32, borderRadius: 8, background: `color-mix(in oklab, ${accent} 12%, transparent)`, color: accent, display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 8 }}>
          <Icon name={icon} size={16} />
        </div>
        <div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--fg-1)" }}>{l}</div>
        <div style={{ fontSize: 11.5, color: "var(--fg-3)", marginTop: 4, lineHeight: 1.4 }}>{d}</div>
      </button>
    );
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ width: 480, maxWidth: "calc(100vw - 32px)", padding: 24 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 6 }}>
          <h3 style={{ margin: 0, fontSize: 17, fontWeight: 600 }}>Criar conta</h3>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16}/></button>
        </div>
        <p style={{ fontSize: 12.5, color: "var(--fg-3)", margin: "0 0 18px" }}>
          Você pode criar quantas contas quiser depois e alternar entre elas.
        </p>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 20 }}>
          <TypeCard k="business" l="Empresarial" d="Para sua empresa, MEI ou escritório" icon="briefcase" />
          <TypeCard k="personal" l="Pessoal" d="Para você, família ou orçamento doméstico" icon="person" />
        </div>

        <div style={{ display: "grid", gap: 14, marginBottom: 16 }}>
          {isBusiness ? (
            <>
              <FormField label="Nome fantasia" required help="Nome comercial — é o que aparece na barra lateral">
                <input className="input" value={name} onChange={e => setName(e.target.value)} autoFocus placeholder="Ex: Locadora Nova Era" style={{ width: "100%", boxSizing: "border-box" }} />
              </FormField>
              <FormField label="Razão social (opcional)" help="Nome legal completo registrado na Receita">
                <input className="input" value={fullName} onChange={e => setFullName(e.target.value)} placeholder="Ex: Locadora Nova Era LTDA — ME" style={{ width: "100%", boxSizing: "border-box" }} />
              </FormField>
            </>
          ) : (
            <>
              <FormField label="Apelido da conta" required help="Como vamos chamar essa conta na barra lateral">
                <input className="input" value={name} onChange={e => setName(e.target.value)} autoFocus placeholder="Ex: Pessoal, Família, Eu" style={{ width: "100%", boxSizing: "border-box" }} />
              </FormField>
              <FormField label="Membros (opcional)" help="Quem usa essa conta — separado por vírgula. Vira opção ao lançar uma despesa.">
                <input className="input" value={members} onChange={e => setMembers(e.target.value)} placeholder="Ex: Pedro, Ana, João" style={{ width: "100%", boxSizing: "border-box" }} />
              </FormField>
              <FormField label="Limite mensal de gasto (opcional)" help="Aparece como meta no dashboard. Pode mudar depois.">
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ color: "var(--fg-3)", fontSize: 13 }}>R$</span>
                  <input className="input" type="text" inputMode="decimal" value={monthlyGoal} onChange={e => setMonthlyGoal(e.target.value)} placeholder="Ex: 5000" style={{ width: "100%", boxSizing: "border-box" }} />
                </div>
              </FormField>
            </>
          )}
          <FormField label="Cor de destaque">
            <div style={{ display: "flex", gap: 8 }}>
              {["#0f172a", "#16a34a", "#b45309", "#7c3aed", "#0ea5e9", "#dc2626", "#0891b2"].map(c => (
                <button key={c} type="button" onClick={() => setAccent(c)}
                  style={{ width: 32, height: 32, borderRadius: 8, background: c,
                    border: accent === c ? "2px solid var(--fg-1)" : "1px solid var(--border)",
                    cursor: "pointer", padding: 0 }} />
              ))}
            </div>
          </FormField>
        </div>

        {err && (
          <div style={{ padding: "10px 12px", background: "color-mix(in oklab, var(--danger) 8%, transparent)", border: "1px solid color-mix(in oklab, var(--danger) 25%, transparent)", borderRadius: 8, fontSize: 12.5, color: "var(--danger)", marginBottom: 14 }}>
            {err}
          </div>
        )}

        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn-ghost" onClick={onClose}>Cancelar</button>
          <button className="btn-primary" onClick={submit} disabled={loading || !name.trim()} style={{ opacity: (loading || !name.trim()) ? 0.6 : 1 }}>
            {loading ? "Criando…" : "Criar conta"}
          </button>
        </div>
      </div>
    </div>
  );
}

// Field reutilizável (pequeno helper compartilhado)
function Field({ label, children }) {
  return (
    <label style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <span style={{ fontSize: 11.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 500 }}>{label}</span>
      {children}
    </label>
  );
}

// FormField: como Field, mas com asterisco de obrigatório e texto de ajuda
function FormField({ label, required, help, children }) {
  return (
    <div>
      <div style={{ fontSize: 11.5, color: "var(--fg-3)", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 500, marginBottom: 6 }}>
        {label} {required && <span style={{ color: "var(--danger)" }}>*</span>}
      </div>
      {children}
      {help && <div style={{ fontSize: 11, color: "var(--fg-3)", marginTop: 4 }}>{help}</div>}
    </div>
  );
}

// Bootstrap: AuthGate envolve App. App só renderiza se houver sessão ativa.
function Root() {
  const [user, setUser] = React.useState(null);
  React.useEffect(() => {
    window.db.auth.getUser().then(u => setUser(u));
    const { data: sub } = window.db.auth.onAuthStateChange((_event, s) => setUser(s?.user || null));
    return () => sub?.subscription?.unsubscribe();
  }, []);
  return (
    <AuthGate>
      {user && <App user={user} />}
    </AuthGate>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<Root />);
