/**
 * Web client root — ticket #13, lot F2. Mounted (instead of the desktop `App`)
 * only when the HTTP transport is selected (`VITE_TRANSPORT="http"`).
 *
 * Routes on the {@link WebSession} paired flag: not paired ⇒ {@link PairingScreen};
 * paired ⇒ the read-only {@link WebWorkspace}. It subscribes to the session's
 * `onUnauthorized` signal so a `401` from any `/api/invoke` (expired/missing
 * cookie) drops back to pairing automatically. "Se déconnecter" (F6) revokes the
 * server session (`POST /api/logout`), tears down the live WS singleton, and
 * returns to pairing.
 *
 * "Appareils" (#77) mounts the shared {@link DevicesScreen} — the same component
 * the desktop shows under `Paramètres → Appareils`. It is what makes a headless
 * install usable: generating a pairing code from an already-paired phone instead
 * of restarting the server with `--new-code`.
 */

import { useCallback, useEffect, useState } from "react";

import { Button } from "@/shared";
import { disconnectWebLive, getWebSession, type WebSession } from "@/adapters/http";
import { DevicesScreen } from "@/features/devices";
import { PairingScreen } from "./PairingScreen";
import { WebWorkspace } from "./WebWorkspace";

interface WebAppProps {
  /** Injectable session (tests); defaults to the shared singleton. */
  session?: WebSession;
}

export function WebApp({ session }: WebAppProps = {}) {
  const webSession = session ?? getWebSession();
  const [paired, setPaired] = useState(() => webSession.isPaired());
  const [signingOut, setSigningOut] = useState(false);
  const [showDevices, setShowDevices] = useState(false);

  useEffect(() => {
    // A 401 anywhere clears the flag and fires this: return to pairing. The live
    // WS is torn down by the composition-root 401 handler (F6). This is also the
    // path for a *suffered* revocation (#77): another device revoked us, the
    // server rejects the next call, and we land back on pairing.
    return webSession.onUnauthorized(() => {
      setShowDevices(false);
      setPaired(false);
    });
  }, [webSession]);

  async function signOut(): Promise<void> {
    if (signingOut) return;
    setSigningOut(true);
    try {
      // Revoke the server session (best-effort), then drop the live socket so it
      // stops reconnecting, and return to pairing regardless of the outcome.
      await webSession.logout();
    } finally {
      disconnectWebLive();
      setSigningOut(false);
      setShowDevices(false);
      setPaired(false);
    }
  }

  /**
   * This device just revoked itself (#77) — a nominal action, not an edge case.
   * The cookie is already dead server-side; drop the local flag and the live
   * socket so nothing keeps retrying, and land on pairing immediately rather
   * than waiting for the next request to 401.
   */
  const onSessionEnded = useCallback(() => {
    webSession.forget();
    disconnectWebLive();
    setShowDevices(false);
    setPaired(false);
  }, [webSession]);

  return (
    <div className="flex h-full flex-col bg-canvas text-content">
      <header
        data-testid="web-header"
        className="flex shrink-0 items-center justify-between border-b border-border px-4 py-3 pt-[max(0.75rem,env(safe-area-inset-top))] pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] sm:px-6"
      >
        <div className="flex items-baseline gap-2">
          <h1 className="text-base font-semibold tracking-tight sm:text-lg">IdeA</h1>
          <span className="rounded-md bg-raised px-1.5 py-0.5 text-[0.65rem] font-medium uppercase text-muted">
            web
          </span>
        </div>
        {paired && (
          <div className="flex items-center gap-1">
            <Button
              variant="ghost"
              size="sm"
              aria-pressed={showDevices}
              onClick={() => setShowDevices((v) => !v)}
            >
              {showDevices ? "Projets" : "Appareils"}
            </Button>
            <Button variant="ghost" size="sm" loading={signingOut} onClick={() => void signOut()}>
              Se déconnecter
            </Button>
          </div>
        )}
      </header>

      <div className="flex flex-1 flex-col overflow-hidden">
        {!paired ? (
          <PairingScreen session={webSession} onPaired={() => setPaired(true)} />
        ) : showDevices ? (
          <div className="h-full overflow-y-auto p-4 pb-[max(1rem,env(safe-area-inset-bottom))] pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] sm:p-6">
            <DevicesScreen onSessionEnded={onSessionEnded} />
          </div>
        ) : (
          <WebWorkspace />
        )}
      </div>
    </div>
  );
}
