<script lang="ts">
  import "../app.css";
  import { page } from "$app/stores";
  import { goto } from "$app/navigation";
  import { onMount, onDestroy, setContext } from "svelte";
  import { get } from "svelte/store";
  import ToastContainer from "$lib/components/ToastContainer.svelte";
  import CommandPalette from "$lib/components/CommandPalette.svelte";
  import { commandPalette } from "$lib/stores/command-palette.js";
  import { toast } from "$lib/stores/toast-store.js";
  import { startApprovalWatcher } from "$lib/stores/approval-watcher.js";
  import { startInteractionWatcher } from "$lib/stores/interaction-watcher.js";
  import { settings, type CortexSettings } from "$lib/stores/settings.js";
  import { createWsClient } from "$lib/stores/ws-client.js";
  import { createAgentStore, beaconDeskRunLabel } from "$lib/stores/agent-store.js";
  import { createStageStore } from "$lib/stores/stage-store.js";
  import type { AgentStore } from "$lib/stores/agent-store.js";
  import type { StageStore } from "$lib/stores/stage-store.js";

  let { children } = $props();

  const agentStore: AgentStore = createAgentStore();
  const stageStore: StageStore = createStageStore();

  setContext("agentStore", agentStore);
  setContext("stageStore", stageStore);

  let wsUnsub: (() => void) | null = null;
  let refreshTimer: ReturnType<typeof setInterval> | null = null;
  let stopApprovalWatcher: (() => void) | null = null;
  let stopInteractionWatcher: (() => void) | null = null;
  const wsClient = createWsClient("/ws/live/cortex-broadcast");

  const navItems = [
    { label: "Beacon", href: "/", icon: "radar" },
    { label: "Chat", href: "/chat", icon: "chat" },
    { label: "Trace", href: "/runs", icon: "alt_route" },
    { label: "Lab", href: "/lab", icon: "science" },
  ];

  let isDark = $state(true);

  function applyTheme(theme: "dark" | "light") {
    isDark = theme === "dark";
    if (typeof document !== "undefined") {
      // Toggle the .dark class — Tailwind reads this for dark: variants
      document.documentElement.classList.toggle("dark", isDark);
      // Also set data-theme for any CSS selectors that use it
      document.documentElement.setAttribute("data-theme", theme);
    }
  }

  function toggleTheme() {
    const next = isDark ? "light" : "dark";
    applyTheme(next);
    settings.save({ theme: next });
  }

  function handleGlobalKeydown(e: KeyboardEvent) {
    // Command palette: always available (even from inputs). Use `code` so layout/locale match physical K.
    if ((e.metaKey || e.ctrlKey) && e.code === "KeyK") {
      e.preventDefault();
      commandPalette.toggle();
      return;
    }
    const tag = (e.target as HTMLElement)?.tagName?.toLowerCase();
    const isInput =
      tag === "input" || tag === "textarea" || tag === "select" || (e.target as HTMLElement)?.isContentEditable;
    if (isInput) return;
    // R — go to Beacon and focus input bar (defer so +page / BottomInputBar can bind)
    if (e.key === "r" || e.key === "R") {
      e.preventDefault();
      const fireFocus = () =>
        window.dispatchEvent(new CustomEvent("cortex:focus-input"));
      if (get(page).url.pathname !== "/") {
        void goto("/").then(() => {
          requestAnimationFrame(() => setTimeout(fireFocus, 50));
        });
      } else {
        // Same route: allow Svelte to flush (e.g. empty beacon) before Beacon focuses input
        requestAnimationFrame(() => setTimeout(fireFocus, 50));
      }
    }
  }

  function refreshAgentsSoon() {
    if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
    void agentStore.refresh();
  }

  onMount(() => {
    settings.init(); // warm up from localStorage before any submitPrompt call

    // Apply saved theme immediately
    const s: CortexSettings = settings.get();
    applyTheme(s.theme);

    stageStore.setNavigate((path) => goto(path));
    // Durable-HITL: app-wide interactive approval toasts (Approve/Deny).
    stopApprovalWatcher = startApprovalWatcher();
    // Durable-HITL: app-wide `request_user_input` polling (feeds InteractPanel).
    stopInteractionWatcher = startInteractionWatcher();
    window.addEventListener("keydown", handleGlobalKeydown);
    window.addEventListener("cortex:toggle-theme", toggleTheme as EventListener);
    window.addEventListener("focus", refreshAgentsSoon);
    window.addEventListener("online", refreshAgentsSoon);
    document.addEventListener("visibilitychange", refreshAgentsSoon);

    wsUnsub = wsClient.onMessage((raw) => {
      const msg = raw as {
        agentId?: string;
        runId?: string;
        type?: string;
        payload?: Record<string, unknown>;
      };
      if (!msg?.agentId || !msg.runId || !msg.type) return;

      agentStore.handleLiveMessage({
        agentId: msg.agentId,
        runId: msg.runId,
        type: msg.type,
        payload: msg.payload ?? {},
      });

      const agents = get(agentStore);
      const node = agents.find((a) => a.runId === msg.runId);

      // Toasts for key lifecycle events
      if (msg.type === "AgentConnected") {
        stageStore.handleAgentConnected(
          node ??
            ({
              agentId: msg.agentId!,
              runId: msg.runId!,
              name: beaconDeskRunLabel({
                agentId: msg.agentId!,
                runId: msg.runId!,
              }),
              state: "running",
              entropy: 0,
              loopIteration: 0,
              reasoningSteps: 0,
              maxIterations: 10,
              tokensUsed: 0,
              cost: 0,
              connectedAt: Date.now(),
              lastEventAt: Date.now(),
            } as import("$lib/stores/agent-store.js").AgentNode),
          agents.length,
        );
        toast.connection(
          `${(node?.name ?? msg.agentId!).slice(0, 28)} connected`,
          "Agent is streaming to Cortex",
          { label: "View run", href: `/run/${msg.runId}` },
        );
      } else if (msg.type === "AgentCompleted") {
        const success = (msg.payload as any)?.success !== false;
        const agentName = node?.name ?? msg.agentId!.slice(0, 20);
        if (success) {
          toast.success(`${agentName} completed`, undefined, { label: "View run", href: `/run/${msg.runId}` });
        } else {
          toast.error(`${agentName} failed`, undefined, { label: "View run", href: `/run/${msg.runId}` });
        }
      } else if (msg.type === "TaskFailed") {
        toast.error(
          `Run failed`,
          typeof (msg.payload as any)?.error === "string" ? (msg.payload as any).error.slice(0, 80) : undefined,
          { label: "View run", href: `/run/${msg.runId}` },
        );
      }
    });

    commandPalette.register([
      {
        id: "nav:beacon",
        label: "Go to Beacon",
        description: "Agent grid and live status",
        icon: "radar",
        keywords: ["beacon", "home", "agents", "grid"],
        action: () => void goto("/"),
      },
      {
        id: "nav:chat",
        label: "New Chat",
        description: "Start a new agent conversation",
        icon: "chat",
        keywords: ["chat", "conversation", "new"],
        action: () => void goto("/chat"),
      },
      {
        id: "nav:runs",
        label: "Execution Trace",
        description: "Browse all agent runs",
        icon: "alt_route",
        keywords: ["runs", "trace", "history"],
        action: () => void goto("/runs"),
      },
      {
        id: "nav:lab",
        label: "Open Lab",
        description: "Build and configure agents",
        icon: "science",
        keywords: ["lab", "builder", "configure"],
        action: () => void goto("/lab"),
      },
      {
        id: "nav:prompts",
        label: "Prompt Library",
        description: "Manage reusable prompts",
        icon: "menu_book",
        keywords: ["prompts", "library", "templates", "snippets"],
        action: () => {
          void goto("/lab#prompts");
          // Covers the already-on-/lab case where goto() won't remount the page
          window.dispatchEvent(new CustomEvent("cortex:lab-tab", { detail: "prompts" }));
        },
      },
      {
        id: "nav:settings",
        label: "Settings",
        description: "Configure Cortex",
        icon: "settings",
        keywords: ["settings", "config", "preferences"],
        action: () => void goto("/settings"),
      },
    ]);

    // Safety-net reconciliation so deletes/new runs reflect without manual reload
    // even if a WS message is missed during navigation transitions.
    refreshTimer = setInterval(() => {
      void agentStore.refresh();
    }, 5000);

    return () => {
      window.removeEventListener("keydown", handleGlobalKeydown);
      window.removeEventListener("cortex:toggle-theme", toggleTheme as EventListener);
      window.removeEventListener("focus", refreshAgentsSoon);
      window.removeEventListener("online", refreshAgentsSoon);
      document.removeEventListener("visibilitychange", refreshAgentsSoon);
      wsUnsub?.();
      wsUnsub = null;
      stopApprovalWatcher?.();
      stopApprovalWatcher = null;
      stopInteractionWatcher?.();
      stopInteractionWatcher = null;
      if (refreshTimer) {
        clearInterval(refreshTimer);
        refreshTimer = null;
      }
    };
  });

  onDestroy(() => {
    wsClient.close();
    agentStore.destroy();
  });
</script>

<div class="h-screen w-screen flex flex-col overflow-hidden cortex-shell-bg text-on-surface">
  <header
    class="cortex-nav flex justify-between items-center w-full px-4 sm:px-6 h-[3.25rem] border-b border-[var(--cortex-border)] shadow-[0_1px_0_rgba(0,0,0,0.12)] dark:shadow-[0_1px_0_rgba(255,255,255,0.04)] z-50 flex-shrink-0 gap-2"
  >
    <!-- RA neural network logo + wordmark (matches docs site identity) -->
    <a
      href="/"
      class="flex items-center gap-2.5 no-underline group flex-shrink-0 rounded-md -ml-1 px-1 py-0.5"
      aria-label="Cortex home"
    >
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="22" height="22" class="flex-shrink-0" aria-hidden="true">
        <defs>
          <linearGradient id="lh-ed" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" stop-color="#8b5cf6" stop-opacity="0.8"/><stop offset="100%" stop-color="#06b6d4" stop-opacity="0.35"/>
          </linearGradient>
          <linearGradient id="lh-ed2" x1="100%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stop-color="#06b6d4" stop-opacity="0.6"/><stop offset="100%" stop-color="#8b5cf6" stop-opacity="0.25"/>
          </linearGradient>
          <filter id="lh-gN" x="-60%" y="-60%" width="220%" height="220%">
            <feGaussianBlur stdDeviation="1.2" result="b"/>
            <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
          </filter>
        </defs>
        <circle cx="24" cy="24" r="18" fill="#8b5cf6" opacity="0.05"/>
        <line x1="14" y1="6" x2="34" y2="6" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="14" y1="6" x2="6" y2="20" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="34" y1="6" x2="42" y2="20" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="6" y1="20" x2="6" y2="34" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="42" y1="20" x2="42" y2="34" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="6" y1="34" x2="18" y2="44" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="42" y1="34" x2="30" y2="44" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="18" y1="44" x2="30" y2="44" stroke="url(#lh-ed)" stroke-width="1.1" stroke-linecap="round"/>
        <line x1="14" y1="6" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="34" y1="6" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="6" y1="20" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="42" y1="20" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="6" y1="34" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="42" y1="34" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="18" y1="44" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <line x1="30" y1="44" x2="24" y2="24" stroke="url(#lh-ed2)" stroke-width="1.3" stroke-linecap="round"/>
        <circle cx="14" cy="6" r="2.5" fill="#8b5cf6" filter="url(#lh-gN)"/>
        <circle cx="34" cy="6" r="2.5" fill="#06b6d4" filter="url(#lh-gN)"/>
        <circle cx="6" cy="20" r="2" fill="#a78bfa" filter="url(#lh-gN)"/>
        <circle cx="42" cy="20" r="2" fill="#c4b5fd" filter="url(#lh-gN)"/>
        <circle cx="6" cy="34" r="2" fill="#06b6d4" filter="url(#lh-gN)"/>
        <circle cx="42" cy="34" r="2" fill="#8b5cf6" filter="url(#lh-gN)"/>
        <circle cx="18" cy="44" r="2.5" fill="#a78bfa" filter="url(#lh-gN)"/>
        <circle cx="30" cy="44" r="2.5" fill="#06b6d4" filter="url(#lh-gN)"/>
        <circle cx="24" cy="24" r="4.8" fill="#8b5cf6" opacity="0.9"/>
        <circle cx="24" cy="24" r="7.5" fill="none" stroke="#06b6d4" stroke-width="0.5" opacity="0.2"/>
      </svg>
      <span class="text-[1.05rem] font-display font-semibold tracking-tight ra-gradient-text uppercase select-none">
        Cortex
      </span>
    </a>

    <nav
      class="cortex-no-scrollbar flex flex-1 min-w-0 items-center justify-center md:justify-center overflow-x-auto"
      aria-label="Primary"
    >
      <div
        class="inline-flex items-center gap-0.5 rounded-lg bg-white/80 dark:bg-surface-container-low/45 px-1 py-0.5 backdrop-blur-sm
               shadow-[0_0_0_1px_rgba(124,58,237,0.2),0_0_0_1px_rgba(255,255,255,0.7)_inset]
               dark:shadow-[0_0_0_1px_rgba(139,92,246,0.28),0_0_0_1px_rgba(6,182,212,0.08)_inset]"
      >
        {#each navItems as item}
          {@const active =
            item.href === "/" ? $page.url.pathname === "/" : $page.url.pathname.startsWith(item.href)}
          <a
            href={item.href}
            title={item.label}
            class="flex items-center gap-1.5 whitespace-nowrap rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors duration-150 no-underline sm:gap-2 sm:px-3 sm:text-[13px] {active
              ? 'bg-violet-100/90 dark:bg-primary/14 text-violet-800 dark:text-primary shadow-[inset_0_0_0_1px_rgba(124,58,237,0.22)] dark:shadow-[inset_0_0_0_1px_rgba(139,92,246,0.25)]'
              : 'text-on-surface-variant hover:bg-surface-container-high/80 hover:text-on-surface'}"
            aria-current={active ? "page" : undefined}
          >
            <span class="material-symbols-outlined text-[18px] opacity-80" aria-hidden="true">{item.icon}</span>
            <span class="hidden sm:inline">{item.label}</span>
          </a>
        {/each}
      </div>
    </nav>

    <div class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0">
      <button
        type="button"
        class="hidden sm:inline-flex items-center gap-2 px-2.5 py-1.5 rounded-md cursor-pointer border-0
               bg-gradient-to-r from-violet-100 to-cyan-100 dark:from-violet-950/40 dark:to-cyan-950/30
               text-violet-900 dark:text-cyan-100/90
               shadow-[0_0_0_1px_rgba(124,58,237,0.22),0_2px_10px_rgba(124,58,237,0.08)]
               dark:shadow-[0_0_0_1px_rgba(139,92,246,0.4),0_0_14px_rgba(6,182,212,0.12)]
               hover:shadow-[0_0_0_1px_rgba(6,182,212,0.35),0_4px_14px_rgba(6,182,212,0.12)]
               dark:hover:shadow-[0_0_0_1px_rgba(6,182,212,0.45),0_0_20px_rgba(139,92,246,0.2)]
               hover:text-violet-950 dark:hover:text-cyan-200 transition-all"
        onclick={() => commandPalette.open()}
        title="Command palette (⌘K or Ctrl+K)"
      >
        <span
          class="material-symbols-outlined text-base text-cyan-700 dark:text-secondary/90"
          aria-hidden="true">terminal</span>
        <span class="cortex-kbd hidden md:inline">⌘K</span>
        <span class="cortex-kbd md:hidden">^K</span>
      </button>
      <button
        type="button"
        onclick={toggleTheme}
        class="material-symbols-outlined text-outline hover:text-primary transition-colors p-1.5 rounded-md bg-transparent border-0 cursor-pointer"
        title="Toggle {isDark ? 'light' : 'dark'} mode"
        aria-label="Toggle theme"
      >{isDark ? "light_mode" : "dark_mode"}</button>
      <a
        href="/settings"
        class="material-symbols-outlined text-outline hover:text-primary transition-colors p-1.5 rounded-md inline-flex"
        title="Settings"
        aria-label="Settings">settings</a>
    </div>
  </header>

  <main class="flex-1 overflow-hidden min-h-0">
    {@render children()}
  </main>
</div>

<CommandPalette />
<ToastContainer />
