// View ↔ URL routing table. Order matters — first match wins.
// `paramNames` extract regex capture groups into a params object.
const ROUTES = [
  { regex: /^\/$/,                    view: "landing" },
  { regex: /^\/login$/,               view: "auth" },
  { regex: /^\/privacy$/,             view: "privacy" },
  { regex: /^\/terms$/,               view: "terms" },
  { regex: /^\/nova$/,                view: "onboarding" },
  { regex: /^\/r\/([^/]+)$/,          view: "result",        paramNames: ["thumbnailId"] },
  { regex: /^\/galeria$/,             view: "history" },
  { regex: /^\/avatares$/,            view: "avatars" },
  { regex: /^\/avatares\/novo$/,      view: "avatar-creator" },
  { regex: /^\/avatares\/([^/]+)$/,   view: "avatar-detail",   paramNames: ["avatarId"] },
  { regex: /^\/editor\/([^/]+)$/,     view: "editor",        paramNames: ["thumbnailId"] },
  { regex: /^\/conta$/,               view: "account" },
  { regex: /^\/upgrade$/,             view: "checkout" },
];

function pathToViewState(pathname) {
  for (const r of ROUTES) {
    const m = pathname.match(r.regex);
    if (m) {
      const params = {};
      (r.paramNames || []).forEach((name, i) => {
        params[name] = decodeURIComponent(m[i + 1]);
      });
      return { view: r.view, params };
    }
  }
  return { view: "landing", params: {} };
}

function viewStateToPath(view, params = {}) {
  switch (view) {
    case "landing":         return "/";
    case "auth":            return "/login";
    case "privacy":         return "/privacy";
    case "terms":           return "/terms";
    case "onboarding":      return "/nova";
    case "result":          return `/r/${encodeURIComponent(params.thumbnailId || "")}`;
    case "history":         return "/galeria";
    case "avatars":         return "/avatares";
    case "avatar-creator":  return "/avatares/novo";
    case "avatar-detail":   return `/avatares/${encodeURIComponent(params.avatarId || "")}`;
    case "editor":          return `/editor/${encodeURIComponent(params.thumbnailId || "")}`;
    case "account":         return "/conta";
    case "checkout":        return "/upgrade";
    default:                return "/";
  }
}

const App = () => {
  const [{ view, params }, setRoute] = React.useState(() =>
    pathToViewState(window.location.pathname),
  );
  const [pendingUrl, setPendingUrl] = React.useState("");
  const [toast, setToast] = React.useState(null);
  // When the user opens "criar avatar" mid-flow (e.g. from the Onboarding's
  // avatar picker), we route them back here on cancel/save instead of dumping
  // them on the avatar list. Defaults to "avatars" for the standalone path.
  const [avatarCreatorReturn, setAvatarCreatorReturn] = React.useState("avatars");
  const [tweaks, setTweak] = window.useTweaks(window.__TWEAK_DEFAULTS);

  // Auth state — bootstrapped on mount, subscribed to Supabase auth changes.
  const [authReady, setAuthReady] = React.useState(false);
  const [user, setUser] = React.useState(null);
  const [profile, setProfile] = React.useState(null);

  const refreshProfile = React.useCallback(async () => {
    try {
      const p = await window.gtAPI.fetch("/me");
      setProfile(p);
    } catch (e) {
      console.error("profile fetch failed:", e);
    }
  }, []);

  // Push URL + update state. Pass params for routes that need them (e.g. result).
  const nav = React.useCallback((newView, newParams = {}) => {
    const path = viewStateToPath(newView, newParams);
    if (path !== window.location.pathname) {
      window.history.pushState({}, "", path);
    }
    setRoute({ view: newView, params: newParams });
    window.scrollTo(0, 0);
  }, []);

  // Browser back/forward → re-derive view from URL.
  React.useEffect(() => {
    const onPop = () => setRoute(pathToViewState(window.location.pathname));
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, []);

  // Stripe Checkout returns the user to /conta?stripe=success|cancel — using
  // a query flag (not a /billing/* path) avoids colliding with the auth-gated
  // billing API route group on the same prefix.
  const stripeReturnHandled = React.useRef(false);
  React.useEffect(() => {
    if (!authReady || !user || stripeReturnHandled.current) return;
    const params = new URLSearchParams(window.location.search);
    const stripeFlag = params.get("stripe");
    if (!stripeFlag) return;
    stripeReturnHandled.current = true;
    if (stripeFlag === "success") {
      setToast("Pagamento confirmado · créditos liberados");
      // Webhook needs a moment to land before the profile refetch picks up the
      // new balance.
      setTimeout(() => { refreshProfile(); }, 1500);
    } else if (stripeFlag === "cancel") {
      setToast("Pagamento cancelado");
    }
    // Clean the query so a refresh doesn't re-toast.
    window.history.replaceState({}, "", "/conta");
    nav("account");
  }, [authReady, user, nav, refreshProfile]);

  React.useEffect(() => {
    let active = true;
    (async () => {
      try {
        await window.gtAPI.bootstrap();
        const u = await window.gtAuth.getUser();
        if (!active) return;
        setUser(u);
        // If we have a pending intent (set before redirecting to OAuth) and the
        // user is now signed in, restore them to where they were going. Intent
        // is stored as a path (so result/:id etc. round-trips through OAuth).
        if (u) {
          let intent = null;
          try { intent = window.localStorage.getItem("gt_pending_intent"); } catch (_) {}
          if (intent) {
            try { window.localStorage.removeItem("gt_pending_intent"); } catch (_) {}
            const target = pathToViewState(intent);
            nav(target.view, target.params);
          }
        }
      } catch (e) {
        console.error("bootstrap failed:", e);
      } finally {
        if (active) setAuthReady(true);
      }
    })();
    const unsub = window.gtAuth.onAuthChange((u, event) => {
      if (!active) return;
      setUser(u);
      if (event === "SIGNED_OUT") { setProfile(null); nav("landing"); }
    });
    return () => { active = false; unsub(); };
  }, [nav]);

  // Load profile (credits, plan) once we have a user.
  React.useEffect(() => {
    if (user) refreshProfile();
    else setProfile(null);
  }, [user, refreshProfile]);

  // Apply brand color tweak as CSS var
  React.useEffect(() => {
    document.documentElement.style.setProperty("--brand", tweaks.brandColor);
  }, [tweaks.brandColor]);
  React.useEffect(() => {
    document.documentElement.dataset.density = tweaks.density;
  }, [tweaks.density]);

  // If the user lands on a shell URL while logged out, stash where they wanted
  // to go so we can restore it after OAuth.
  // Public legal pages render outside the auth gate and without the app shell.
  const isLegal = view === "privacy" || view === "terms";
  const isShell = view !== "landing" && !isLegal;
  const showAuth = view === "auth" || (isShell && !user);
  React.useEffect(() => {
    if (!authReady) return;
    if (isShell && !user && view !== "auth") {
      try { window.localStorage.setItem("gt_pending_intent", window.location.pathname); } catch (_) {}
    }
  }, [authReady, isShell, user, view]);

  const showToast = (msg) => setToast(msg);

  const stashIntent = (path) => {
    try { window.localStorage.setItem("gt_pending_intent", path); } catch (_) {}
  };

  const requireAuthFor = (intendedView, intendedParams) => {
    if (user) { nav(intendedView, intendedParams); return; }
    stashIntent(viewStateToPath(intendedView, intendedParams));
    nav("auth");
  };

  const startFromUrl = (url) => {
    setPendingUrl(url || "demo");
    if (!user) { stashIntent(viewStateToPath("onboarding")); nav("auth"); return; }
    nav("onboarding");
  };
  const openEditor = (target) => {
    const id = target?.thumbnailId || target?.id;
    if (!id) return;
    nav("editor", { thumbnailId: id });
  };

  const handleLogout = async () => {
    try { await window.gtAuth.signOut(); } catch (_) {}
  };

  // Legal pages are static and public — render immediately, before the auth
  // bootstrap resolves, so they're shareable and indexable without a session.
  if (isLegal) {
    const goHome = () => nav("landing");
    return view === "privacy"
      ? <window.PrivacyPage onHome={goHome} />
      : <window.TermsPage onHome={goHome} />;
  }

  if (!authReady) {
    return <div style={{minHeight: "100vh", display: "grid", placeItems: "center", background: "var(--bg)"}}>
      <div className="muted-2 mono" style={{fontSize: 12}}>Carregando…</div>
    </div>;
  }

  if (showAuth) {
    return <>
      <AuthScreen />
      {toast && <Toast msg={toast} onDone={() => setToast(null)} />}
    </>;
  }

  return <>
    {!isShell && (
      <Landing
        onStart={(u) => startFromUrl(u)}
        onPricing={() => requireAuthFor("checkout")}
        onPlatform={() => requireAuthFor("onboarding")}
      />
    )}
    {isShell && (
      <div className="app" data-density={tweaks.density}>
        <Sidebar view={view} onNav={nav} tweaks={tweaks} profile={profile} />
        <div className="main">
          <header className="topbar">
            <div className="title">{({
              onboarding: "Nova Thumbnail",
              result: "Thumbnail Pronta",
              editor: "Editor",
              avatars: "Avatares",
              "avatar-creator": "Criar Avatar",
              "avatar-detail": "Avatar",
              history: "Galeria",
              account: "Conta",
              checkout: "Upgrade",
            })[view]}</div>
            <span className="subtitle muted">{window.location.pathname}</span>
            <div className="spacer" />
            <button className="btn btn-sm" onClick={() => nav("checkout")}>
              <span className="mono" style={{fontSize: 11, color: "var(--text-3)"}}>
                {profile ? `${profile.credits_remaining} créditos` : "—"}
              </span>
            </button>
            <button className="btn btn-sm btn-primary" onClick={() => nav("onboarding")}>
              <Icon name="sparkles" size={14} /> Nova
            </button>
            <div style={{width: 36, height: 36, borderRadius: "50%", overflow: "hidden", cursor: "pointer"}} onClick={() => nav("account")}>
              {user?.user_metadata?.avatar_url
                ? <img src={user.user_metadata.avatar_url} alt="" referrerPolicy="no-referrer" style={{width: "100%", height: "100%", objectFit: "cover"}} />
                : <FacePlaceholder tone={0} emotion="happy" size={36} />}
            </div>
          </header>

          <div className="content">
            {view === "onboarding" && <Onboarding
              initialUrl={pendingUrl}
              isPro={profile?.plan === "plan_120"}
              credits={profile?.credits_remaining ?? 0}
              onGenerate={(opts) => { refreshProfile(); nav("result", { thumbnailId: opts?.thumbnailId }); }}
              onCreateAvatar={() => { setAvatarCreatorReturn("onboarding"); nav("avatar-creator"); }}
              onUpgrade={() => nav("checkout")}
            />}
            {view === "result" && <ThumbResult
              result={{ thumbnailId: params.thumbnailId }}
              onEdit={openEditor}
              onDownload={showToast}
              onNew={() => { setPendingUrl(""); nav("onboarding"); }}
            />}
            {view === "editor" && <Editor
              thumbnailId={params.thumbnailId}
              onDownload={showToast}
              onBack={() => nav("history")}
              userAvatarUrl={user?.user_metadata?.avatar_url || user?.user_metadata?.picture}
            />}
            {view === "avatars" && <AvatarLibrary
              onCreate={() => { setAvatarCreatorReturn("avatars"); nav("avatar-creator"); }}
              onOpen={(id) => nav("avatar-detail", { avatarId: id })}
            />}
            {view === "avatar-creator" && <AvatarCreator
              onSave={(avatar) => { showToast(`Avatar "${avatar.name}" criado`); refreshProfile(); nav(avatarCreatorReturn); }}
              onCancel={() => nav(avatarCreatorReturn)}
            />}
            {view === "avatar-detail" && <window.AvatarDetail
              avatarId={params.avatarId}
              onBack={() => nav("avatars")}
              onDeleted={() => { showToast("Avatar apagado"); nav("avatars"); }}
              onUseInThumb={() => nav("onboarding")}
            />}
            {view === "history" && <HistoryScreen
              onEdit={openEditor}
              onDownload={showToast}
              userAvatarUrl={user?.user_metadata?.avatar_url || user?.user_metadata?.picture}
            />}
            {view === "account" && <Account
              onUpgrade={() => nav("checkout")}
              onLogout={handleLogout}
              user={user}
              profile={profile}
              onProfileChange={refreshProfile}
            />}
            {view === "checkout" && <Checkout onComplete={(msg) => { showToast(msg); nav("account"); }} onBack={() => nav("account")} />}
          </div>
        </div>
      </div>
    )}

    {toast && <Toast msg={toast} onDone={() => setToast(null)} />}

    {/* Tweaks panel */}
    <window.TweaksPanel title="Tweaks">
      <window.TweakSection label="Marca">
        <window.TweakColor
          label="Vermelho da marca"
          value={tweaks.brandColor}
          onChange={(v) => setTweak("brandColor", v)}
          options={["#FF3B30", "#E11D48", "#F97316"]}
        />
      </window.TweakSection>
      <window.TweakSection label="Layout">
        <window.TweakRadio
          label="Densidade"
          value={tweaks.density}
          onChange={(v) => setTweak("density", v)}
          options={[{value: "comfortable", label: "Conforto"}, {value: "compact", label: "Compacto"}]}
        />
        <window.TweakToggle
          label="Card de plano na sidebar"
          value={tweaks.showSidebarBadge}
          onChange={(v) => setTweak("showSidebarBadge", v)}
        />
      </window.TweakSection>
      <window.TweakSection label="Navegação">
        <div className="col-gap" style={{gap: 6}}>
          {[
            ["landing", "🏠 Landing"],
            ["onboarding", "🔗 Colar URL"],
            ["history", "🖼  Galeria"],
            ["avatars", "👥 Avatares"],
            ["avatar-creator", "✨ Criar Avatar"],
            ["account", "⚙️  Conta"],
            ["checkout", "💳 Checkout"],
          ].map(([v, l]) => (
            <button key={v} className={"btn btn-sm " + (view === v ? "btn-primary" : "")} onClick={() => nav(v)} style={{justifyContent: "flex-start"}}>{l}</button>
          ))}
        </div>
      </window.TweakSection>
    </window.TweaksPanel>
  </>;
};

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