import "@mariozechner/mini-lit/dist/ThemeToggle.js";
import { Agent, type AgentMessage } from "@jaeswift/jae-agent-core";
import { getModel } from "@jaeswift/jae-ai";
import {
  type AgentState,
  ApiKeyPromptDialog,
  AppStorage,
  ChatPanel,
  CustomProvidersStore,
  createJavaScriptReplTool,
  IndexedDBStorageBackend,
  ModelSelector,
  ProviderKeysStore,
  ProvidersModelsTab,
  ProxyTab,
  SessionListDialog,
  SessionsStore,
  SettingsDialog,
  SettingsStore,
  setAppStorage,
} from "@jaeswift/jae-web-ui";
import { html, render } from "lit";
import { Brain, Download, History, Keyboard, Plus, Settings } from "lucide";
import "./app.css";
import {
  createBashTool,
  createBrowserTool,
  createImageGenTool,
  createMemoryTools,
  createTTSTool,
  createWebSearchTool,
} from "@jaeswift/jae-web-ui";
import { icon } from "@mariozechner/mini-lit";
import { Button } from "@mariozechner/mini-lit/dist/Button.js";
import { Input } from "@mariozechner/mini-lit/dist/Input.js";
import type { CommandPalette } from "./components/command-palette.js";
import type { CostTracker } from "./components/cost-tracker.js";
import type { KeyboardShortcuts } from "./components/keyboard-shortcuts.js";
import type { MemoryManager } from "./components/memory-manager.js";
import { exportSessionAsJson, exportSessionAsMarkdown } from "./components/session-export.js";
import { customConvertToLlm, registerCustomMessageRenderers } from "./custom-messages.js";
import "./components/command-palette.js";
import "./components/keyboard-shortcuts.js";
import "./components/memory-manager.js";
import "./components/cost-tracker.js";
import { JaeEmptyState } from "./components/empty-state.js";
import type { JaeUtilityToggle, UtilityVisibility } from "./components/utility-toggle.js";
import "./components/empty-state.js";
import "./components/utility-toggle.js";
import type { JaeSessionSidebar } from "./components/session-sidebar.js";
import "./components/session-sidebar.js";
import type { JaeBrowserPanel } from "./components/browser-panel.js";
import type { JaeTerminalPanel } from "./components/terminal-panel.js";
import "./components/browser-panel.js";
import "./components/terminal-panel.js";

// NEW COMPONENTS
import type { JaeCryptoTicker } from "./components/crypto-ticker.js";
import type { JaePersonaSelector } from "./components/persona-selector.js";
import type { JaeSlashCommands } from "./components/slash-commands.js";
import type { JaeMarketplace } from "./components/marketplace.js";
import type { JaeMoodIndicator } from "./components/mood-indicator.js";
import type { JaeTypingIndicator } from "./components/typing-indicator.js";
import type { JaeContextPeek } from "./components/context-peek.js";
import "./components/crypto-ticker.js";
import "./components/persona-selector.js";
import "./components/slash-commands.js";
import "./components/marketplace.js";
import "./components/mood-indicator.js";
import "./components/typing-indicator.js";
import "./components/context-peek.js";

// ===== STORAGE =====
const backend = new IndexedDBStorageBackend();
setAppStorage(new AppStorage(backend));
const sessionsStore = new SessionsStore();
const settingsStore = new SettingsStore();
const providerKeysStore = new ProviderKeysStore();
const customProvidersStore = new CustomProvidersStore();

// ===== STATE =====
let chatPanel: ChatPanel;
let agent: Agent | null = null;
let sidebarWidth = 220;
let rightPanel: "none" | "terminal" | "browser" = "none";
let rightPanelWidth = 420;
let hasMessages = false;
let currentModel = "llama-3.3-70b";
let currentProvider = "venice";
let terminalPanel: JaeTerminalPanel | null = null;
let browserPanel: JaeBrowserPanel | null = null;
let crackActive = false;
let crackOpacity = 1;
let crackTimer: ReturnType<typeof setInterval> | null = null;

// View toggle state
let viewState = {
  tools: true,
  thinking: true,
  system: false,
  timestamps: true,
};

const SYSTEM_PROMPT = `You are JAE, a capable AI coding assistant.
You help users by answering questions, writing code, and using your available tools.

RULES:
- For casual greetings like "hi", "hello", "how are you" - respond conversationally. Do NOT use any tools.
- Only use tools when the user explicitly asks for something that requires them.
- When asked to browse a URL, use the browser tool. When asked to search, use web_search.
- When asked to run commands, use bash. When asked to generate images, use image_gen.
- Be concise and helpful. Use markdown formatting.
- Never create files or run commands unless explicitly asked to do so.`;


// ===== AUTO-MEMORY SYSTEM =====
const AUTO_MEMORY_DB = "jae-auto-memory";
const AUTO_MEMORY_STORE = "entries";

interface AutoMemory {
  id: string;
  content: string;
  tags: string[];
  timestamp: string;
  source: "user" | "agent" | "system";
}

let autoMemoryDb: IDBDatabase | null = null;

async function openAutoMemoryDb(): Promise<IDBDatabase> {
  if (autoMemoryDb) return autoMemoryDb;
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(AUTO_MEMORY_DB, 1);
    req.onupgradeneeded = () => {
      const store = req.result.createObjectStore(AUTO_MEMORY_STORE, { keyPath: "id" });
      store.createIndex("tags", "tags", { multiEntry: true });
      store.createIndex("timestamp", "timestamp");
    };
    req.onsuccess = () => { autoMemoryDb = req.result; resolve(autoMemoryDb); };
    req.onerror = () => reject(req.error);
  });
}

async function autoMemorySave(content: string, tags: string[] = [], source: "user" | "agent" | "system" = "agent"): Promise<void> {
  const db = await openAutoMemoryDb();
  const entry: AutoMemory = { id: crypto.randomUUID(), content, tags, timestamp: new Date().toISOString(), source };
  return new Promise((resolve, reject) => {
    const tx = db.transaction(AUTO_MEMORY_STORE, "readwrite");
    tx.objectStore(AUTO_MEMORY_STORE).put(entry);
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
  });
}

async function autoMemorySearch(query: string, limit = 10): Promise<AutoMemory[]> {
  const db = await openAutoMemoryDb();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(AUTO_MEMORY_STORE, "readonly");
    const req = tx.objectStore(AUTO_MEMORY_STORE).getAll();
    req.onsuccess = () => {
      const q = query.toLowerCase();
      const results = (req.result || []).filter((e: AutoMemory) =>
        e.content.toLowerCase().includes(q) || e.tags.some(t => t.toLowerCase().includes(q))
      ).slice(-limit);
      resolve(results);
    };
    req.onerror = () => reject(req.error);
  });
}

async function autoMemoryGetAll(limit = 50): Promise<AutoMemory[]> {
  const db = await openAutoMemoryDb();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(AUTO_MEMORY_STORE, "readonly");
    const req = tx.objectStore(AUTO_MEMORY_STORE).getAll();
    req.onsuccess = () => resolve((req.result || []).slice(-limit));
    req.onerror = () => reject(req.error);
  });
}

// Extract key facts from messages for auto-learning
function extractKeyFacts(text: string): string[] {
  const facts: string[] = [];
  // Patterns that indicate important information
  const patterns = [
    /my name is ([\w\s]+)/i,
    /i(?:'m| am) a ([\w\s]+)/i,
    /i work (?:at|for|with) ([\w\s]+)/i,
    /i live in ([\w\s]+)/i,
    /i use ([\w\s]+)/i,
    /i prefer ([\w\s]+)/i,
    /remember (?:that )?(.+)/i,
    /my (?:email|phone|address) is ([\w\s@.+]+)/i,
    /the (?:api key|password|token|url|endpoint) is ([^\s]+)/i,
  ];
  for (const p of patterns) {
    const m = text.match(p);
    if (m && m[1]) facts.push(m[0].trim());
  }
  return facts;
}

// Hook into messages to auto-learn
function processMessageForMemory(role: string, text: string) {
  if (!text || text.length < 10) return;
  const facts = extractKeyFacts(text);
  for (const fact of facts) {
    autoMemorySave(fact, ["auto-learned", role], role === "user" ? "user" : "agent");
  }
}

// Inject memories into system prompt
async function getMemoryAugmentedPrompt(basePrompt: string, userMessage: string): Promise<string> {
  try {
    const relevant = await autoMemorySearch(userMessage, 5);
    if (relevant.length === 0) return basePrompt;
    const memoryBlock = relevant.map(m => `- ${m.content}`).join("\n");
    return `${basePrompt}

RELEVANT MEMORIES:
${memoryBlock}

Use these memories to provide more personalised and context-aware responses.`;
  } catch {
    return basePrompt;
  }
}

// ===== AGENT CREATION =====
async function createAgent(initialState?: AgentState) {
  const model = initialState?.model || getModel("venice", "llama-3.3-70b");
  if (!model) throw new Error("No model found");

  const replTool = createJavaScriptReplTool();
  const webSearch = createWebSearchTool();
  const imageGen = createImageGenTool();
  const tts = createTTSTool();
  const bash = createBashTool();
  const browser = createBrowserTool();
  const memTools = createMemoryTools();
  const allTools = [replTool, webSearch, imageGen, tts, bash, browser, ...memTools];

  agent = new Agent({
    model,
    systemPrompt: SYSTEM_PROMPT,
    tools: allTools.map((t) => t.tool),
    convertToLlm: customConvertToLlm,
    ...initialState,
  });

  chatPanel.setAgent(agent, {
    toolsFactory: () => allTools,
    convertToLlm: customConvertToLlm,
  });

  registerCustomMessageRenderers(chatPanel);

  currentModel = model.modelId || "llama-3.3-70b";
  currentProvider = model.provider || "venice";

  // Subscribe to agent events for UI state tracking
  agent.subscribe((event) => {
    const typing = document.querySelector("jae-typing-indicator") as JaeTypingIndicator;
    const mood = document.querySelector("jae-mood-indicator") as JaeMoodIndicator;

    switch (event.type) {
      case "agent_start":
        if (typing) typing.show("high");
        break;

      case "agent_end":
        if (typing) typing.hide();
        break;

      case "turn_start":
        if (typing) typing.show("high");
        break;

      case "turn_end":
        if (typing) typing.hide();
        break;

      case "tool_execution_start":
        if (typing) typing.show("medium");
        // Auto-open panels based on tool usage
        if (event.toolName === "browser" || event.toolName === "web_fetch" || event.toolName === "navigate") {
          if (rightPanel !== "browser") {
            rightPanel = "browser";
            renderApp();
          }
        }
        if (event.toolName === "bash") {
          if (rightPanel !== "terminal") {
            rightPanel = "terminal";
            renderApp();
            requestAnimationFrame(() => {
              if (!terminalPanel) terminalPanel = document.querySelector("jae-terminal-panel") as JaeTerminalPanel;
              terminalPanel?.connect();
            });
          }
        }
        break;

      case "message_start": {
        const msg = event.message;
        if (!hasMessages && msg.role === "assistant") {
          hasMessages = true;
          renderApp();
        }
        // Auto-learn from user messages
        if (msg.role === "user" && typeof msg.content === "string") {
          processMessageForMemory("user", msg.content);
        }
        break;
      }

      case "message_end": {
        const msg = event.message;
        // Update mood based on assistant content
        if (mood && msg.role === "assistant" && typeof msg.content === "string") {
          const text = msg.content.toLowerCase();
          if (text.includes("error") || text.includes("failed") || text.includes("cannot")) {
            mood.setMood("frustrated");
          } else if (text.includes("!") || text.includes("great") || text.includes("success") || text.includes("done")) {
            mood.setMood("excited");
          } else if (text.includes("warning") || text.includes("careful") || text.includes("caution")) {
            mood.setMood("warning");
          } else {
            mood.setMood("focused");
          }
        }
        // Track cost from usage data on the message
        const usage = (msg as any).usage;
        if (usage) {
          const costEl = document.querySelector("jae-cost-tracker") as CostTracker;
          if (costEl) {
            costEl.addUsage(usage.input || 0, usage.output || 0);
          }
        }
        break;
      }
    }
  });

  await refreshSidebar();
  renderApp();
}

// ===== SESSION MANAGEMENT =====
async function loadSession(id: string): Promise<boolean> {
  const data = await sessionsStore.get(id);
  if (!data) return false;
  await createAgent(data.state);
  hasMessages = (data.state?.messages?.length || 0) > 0;
  return true;
}

async function saveSession() {
  if (!agent) return;
  const msgs = agent.getMessages();
  const title = msgs.find((m: AgentMessage) => m.role === "user")?.content?.toString().slice(0, 50) || "New chat";
  const state = agent.getState();
  const id = state.sessionId || crypto.randomUUID();
  await sessionsStore.save(id, { state, title });
  const sidebar = document.querySelector("jae-session-sidebar") as JaeSessionSidebar;
  if (sidebar) {
    sidebar.addSession({ id, title, date: new Date().toLocaleDateString(), pinned: false });
    sidebar.setActive(id);
  }
}

async function refreshSidebar() {
  const sidebar = document.querySelector("jae-session-sidebar") as JaeSessionSidebar;
  if (sidebar) sidebar.refresh();
}

function newSession() {
  hasMessages = false;
  createAgent();
}

// ===== COMMANDS =====
function setupCommands() {
  document.addEventListener("keydown", (e: KeyboardEvent) => {
    if ((e.metaKey || e.ctrlKey) && e.key === "k") {
      e.preventDefault();
      const cp = document.querySelector("command-palette") as CommandPalette;
      cp?.toggle();
    }
    if (e.key === "?" && !isInputFocused()) {
      e.preventDefault();
      const ks = document.querySelector("keyboard-shortcuts") as KeyboardShortcuts;
      ks?.toggle();
    }
    if ((e.metaKey || e.ctrlKey) && e.key === "n") {
      e.preventDefault();
      newSession();
    }
    if ((e.metaKey || e.ctrlKey) && e.key === "e") {
      e.preventDefault();
      if (agent) exportSessionAsMarkdown(agent.getMessages());
    }
    if ((e.metaKey || e.ctrlKey) && e.key === "b") {
      e.preventDefault();
      rightPanel = rightPanel === "browser" ? "none" : "browser";
      renderApp();
    }
    if ((e.metaKey || e.ctrlKey) && e.key === "t") {
      e.preventDefault();
      rightPanel = rightPanel === "terminal" ? "none" : "terminal";
      renderApp();
      if (rightPanel === "terminal") {
        requestAnimationFrame(() => {
          if (!terminalPanel) terminalPanel = document.querySelector("jae-terminal-panel") as JaeTerminalPanel;
          terminalPanel?.connect();
        });
      }
    }
    if ((e.metaKey || e.ctrlKey) && e.key === "m") {
      e.preventDefault();
      const mp = document.querySelector("jae-marketplace") as JaeMarketplace;
      mp?.toggle();
    }
  });
}

function isInputFocused(): boolean {
  const el = document.activeElement;
  if (!el) return false;
  const tag = el.tagName.toLowerCase();
  return tag === "input" || tag === "textarea" || (el as HTMLElement).isContentEditable;
}

// ===== SLASH COMMANDS HANDLER =====
function handleSlashCommand(e: CustomEvent) {
  const cmd = e.detail;
  switch (cmd) {
    case "search":
    case "web_search":
      chatPanel?.agentInterface?.setInput("/search ");
      break;
    case "image":
    case "image_gen":
      chatPanel?.agentInterface?.setInput("/image ");
      break;
    case "browser":
      rightPanel = "browser";
      renderApp();
      break;
    case "terminal":
      rightPanel = "terminal";
      renderApp();
      requestAnimationFrame(() => {
        if (!terminalPanel) terminalPanel = document.querySelector("jae-terminal-panel") as JaeTerminalPanel;
        terminalPanel?.connect();
      });
      break;
    case "memory":
      const mm = document.querySelector("memory-manager") as MemoryManager;
      mm?.toggle();
      break;
    case "persona":
      const ps = document.querySelector("jae-persona-selector") as JaePersonaSelector;
      ps?.toggle();
      break;
    case "marketplace":
      const mp = document.querySelector("jae-marketplace") as JaeMarketplace;
      mp?.toggle();
      break;
    case "settings":
      SettingsDialog.open([new ProvidersModelsTab(), new ProxyTab()]);
      break;
    case "export_md":
      if (agent) exportSessionAsMarkdown(agent.getMessages());
      break;
    case "export_json":
      if (agent) exportSessionAsJson(agent.getMessages());
      break;
    case "new_chat":
      newSession();
      break;
    case "help":
      const ks = document.querySelector("keyboard-shortcuts") as KeyboardShortcuts;
      ks?.show();
      break;
    case "clear":
      hasMessages = false;
      createAgent();
      break;
  }
}

// ===== HANDLE SUGGESTION CHIPS =====
function handleSuggestion(e: CustomEvent) {
  const text = e.detail;
  if (chatPanel?.agentInterface) {
    chatPanel.agentInterface.setInput(text);
    const ta = chatPanel.querySelector("textarea");
    if (ta) { ta.value = text; ta.focus(); }
  }
}

// ===== PERSONA CHANGE HANDLER =====
function handlePersonaChange(e: CustomEvent) {
  const persona = e.detail;
  if (agent && persona?.systemPrompt) {
    agent.setSystemPrompt(persona.systemPrompt);
  }
}

// ===== VIEW TOGGLE HANDLER =====
function handleViewChange(e: CustomEvent) {
  const vis = e.detail as UtilityVisibility;
  viewState = {
    tools: vis.showToolCalls,
    thinking: vis.showThinking,
    system: vis.showSystemMessages,
    timestamps: vis.showTimestamps,
  };
  renderApp();
}

// ===== MOOD: ANGRY CRACK EFFECT =====
function triggerCrack() {
  crackActive = true;
  crackOpacity = 1;
  renderApp();
  // Fade over 5 minutes (300 seconds)
  if (crackTimer) clearInterval(crackTimer);
  crackTimer = setInterval(() => {
    crackOpacity = Math.max(0, crackOpacity - (1 / 300));
    const el = document.getElementById("crack-overlay");
    if (el) el.style.opacity = String(crackOpacity);
    if (crackOpacity <= 0) {
      crackActive = false;
      if (crackTimer) clearInterval(crackTimer);
      crackTimer = null;
      renderApp();
    }
  }, 1000);
}

// ===== VIEW TOGGLE CSS CLASSES =====
function getViewClasses(): string {
  const classes: string[] = [];
  if (!viewState.tools) classes.push("hide-tools");
  if (!viewState.thinking) classes.push("hide-thinking");
  if (!viewState.system) classes.push("hide-system");
  if (!viewState.timestamps) classes.push("hide-timestamps");
  // Hide browser tool output in chat when browser panel is visible
  if (rightPanel === "browser") classes.push("browser-panel-active");
  return classes.join(" ");
}

// ===== RENDER =====
const sidebar = document.createElement("jae-session-sidebar") as JaeSessionSidebar;
sidebar.addEventListener("session-select", ((e: CustomEvent) => { loadSession(e.detail); }) as EventListener);
sidebar.addEventListener("session-delete", ((e: CustomEvent) => { sessionsStore.delete(e.detail); }) as EventListener);
sidebar.addEventListener("new-session", () => { newSession(); });

function renderApp() {
  const app = document.getElementById("app");
  if (!app) return;

  render(
    html`
      <div class="flex flex-col h-screen bg-background text-foreground dark">
        <!-- HEADER -->
        <div class="flex items-center gap-2 px-3 shrink-0 border-b border-border/40 jae-glass" style="height:48px">
          <img src="/mascot/jae-default.png" class="w-7 h-7 rounded-full" alt="JAE" style="transition: transform 0.3s" @mouseenter=${(e: Event) => { (e.currentTarget as HTMLElement).style.transform = "scale(1.15) rotate(5deg)"; }} @mouseleave=${(e: Event) => { (e.currentTarget as HTMLElement).style.transform = ""; }} />
          <span class="text-sm font-bold text-foreground tracking-tight">JAE</span>
          <jae-mood-indicator class="ml-1"></jae-mood-indicator>
          <span class="text-[10px] px-2 py-0.5 rounded-full jae-glass-sm text-muted-foreground">${currentProvider}/${currentModel}</span>
          <div class="flex-1"></div>
          <!-- View Toggle -->
          <jae-utility-toggle @visibility-change=${handleViewChange}></jae-utility-toggle>
          ${Button({ variant: "ghost", size: "sm", children: html`<span class="text-[13px]">+</span>`, onClick: () => newSession(), title: "New chat" })}
          ${Button({ variant: "ghost", size: "sm", children: icon(History, "sm"), onClick: () => SessionListDialog.open(sessionsStore), title: "History" })}
          ${Button({ variant: "ghost", size: "sm", children: icon(Download, "sm"), onClick: () => { if (agent) exportSessionAsMarkdown(agent.getMessages()); }, title: "Export" })}
          ${Button({ variant: "ghost", size: "sm", children: icon(Keyboard, "sm"), onClick: () => { const ks = document.querySelector("keyboard-shortcuts") as KeyboardShortcuts; ks?.toggle(); }, title: "Shortcuts" })}
          ${Button({ variant: "ghost", size: "sm", children: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>`, onClick: () => { rightPanel = rightPanel === "browser" ? "none" : "browser"; renderApp(); }, title: "Browser" })}
          ${Button({ variant: "ghost", size: "sm", children: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>`, onClick: () => { rightPanel = rightPanel === "terminal" ? "none" : "terminal"; renderApp(); if (rightPanel === "terminal") requestAnimationFrame(() => { if (!terminalPanel) terminalPanel = document.querySelector("jae-terminal-panel") as JaeTerminalPanel; terminalPanel?.connect(); }); }, title: "Terminal" })}
          ${Button({ variant: "ghost", size: "sm", children: icon(Settings, "sm"), onClick: () => SettingsDialog.open([new ProvidersModelsTab(), new ProxyTab()]), title: "Settings" })}
        </div>

        <!-- MAIN BODY -->
        <div class="flex flex-1 min-h-0 overflow-hidden">
          <!-- SIDEBAR -->
          <div id="sidebar-wrap" style="width:${sidebarWidth}px;min-width:150px;max-width:420px;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid rgba(42,42,64,0.4)" class="jae-glass-sm">
            ${sidebar}
            <!-- Bottom sidebar: Marketplace + Crypto Ticker -->
            <div class="mt-auto border-t border-border/20 shrink-0">
              <button @click=${() => { const mp = document.querySelector("jae-marketplace") as JaeMarketplace; mp?.toggle(); }}
                class="flex items-center gap-2 w-full px-3 py-2 text-xs text-muted-foreground hover:text-foreground hover:bg-secondary/30 transition-all duration-200">
                <span>\ud83d\udecd\ufe0f</span> Marketplace
              </button>
              <jae-crypto-ticker></jae-crypto-ticker>
            </div>
          </div>

          <!-- SIDEBAR RESIZE -->
          <div class="jae-resize-handle"
            @mousedown=${(e: MouseEvent) => {
              e.preventDefault();
              const sx = e.clientX, sw = sidebarWidth;
              const mv = (me: MouseEvent) => { sidebarWidth = Math.max(150, Math.min(420, sw + me.clientX - sx)); const w = document.getElementById("sidebar-wrap"); if (w) w.style.width = sidebarWidth + "px"; };
              const up = () => { document.removeEventListener("mousemove", mv); document.removeEventListener("mouseup", up); renderApp(); };
              document.addEventListener("mousemove", mv);
              document.addEventListener("mouseup", up);
            }}></div>

          <!-- CHAT AREA -->
          <div class="flex flex-col flex-1 min-w-0 min-h-0 relative ${getViewClasses()}">
            ${!hasMessages ? html`
              <div class="absolute inset-x-0 top-0 z-10 flex flex-col" style="bottom:130px" @suggestion=${handleSuggestion}>
                <jae-empty-state style="display:flex;flex-direction:column;flex:1;width:100%;min-height:0"></jae-empty-state>
              </div>
            ` : html``}
            <div id="chat-wrapper" class="flex flex-col flex-1 min-h-0">
              ${chatPanel}
            </div>
            <jae-typing-indicator></jae-typing-indicator>
            <!-- Persona + Slash commands -->
            <jae-slash-commands @command=${handleSlashCommand}></jae-slash-commands>
          </div>

          <!-- RIGHT PANEL -->
          ${rightPanel !== "none" ? html`
            <div class="jae-resize-handle"
              @mousedown=${(e: MouseEvent) => {
                e.preventDefault();
                const sx = e.clientX, sw = rightPanelWidth;
                const mv = (me: MouseEvent) => { rightPanelWidth = Math.max(280, Math.min(800, sw - (me.clientX - sx))); const p = document.getElementById("right-panel"); if (p) p.style.width = rightPanelWidth + "px"; };
                const up = () => { document.removeEventListener("mousemove", mv); document.removeEventListener("mouseup", up); renderApp(); };
                document.addEventListener("mousemove", mv);
                document.addEventListener("mouseup", up);
              }}></div>
            <div id="right-panel" class="flex flex-col border-l border-border/40" style="width:${rightPanelWidth}px;min-width:280px;max-width:800px;flex-shrink:0">
              <div class="flex items-center gap-1 px-2 shrink-0 border-b border-border/30 jae-glass-sm" style="height:36px">
                <button class="text-xs px-2 py-1 rounded transition-all duration-200 ${rightPanel === "terminal" ? "bg-primary text-primary-foreground" : "hover:bg-secondary/40 text-muted-foreground"}" @click=${() => { rightPanel = "terminal"; renderApp(); requestAnimationFrame(() => { if (!terminalPanel) terminalPanel = document.querySelector("jae-terminal-panel") as JaeTerminalPanel; terminalPanel?.connect(); }); }}>Terminal</button>
                <button class="text-xs px-2 py-1 rounded transition-all duration-200 ${rightPanel === "browser" ? "bg-primary text-primary-foreground" : "hover:bg-secondary/40 text-muted-foreground"}" @click=${() => { rightPanel = "browser"; renderApp(); }}>Browser</button>
                <div class="flex-1"></div>
                <button class="text-xs px-2 py-1 rounded hover:bg-secondary/40 text-muted-foreground transition-colors" @click=${() => { rightPanel = "none"; renderApp(); }} title="Close">\u2715</button>
              </div>
              ${rightPanel === "terminal" ? html`<jae-terminal-panel class="flex-1 min-h-0"></jae-terminal-panel>` : html``}
              ${rightPanel === "browser" ? html`<jae-browser-panel class="flex-1 min-h-0"></jae-browser-panel>` : html``}
            </div>
          ` : html``}
        </div>

        <!-- PERSONA SELECTOR (floating) -->
        <jae-persona-selector @persona-change=${handlePersonaChange}></jae-persona-selector>
      </div>

      <!-- OVERLAYS -->
      <command-palette></command-palette>
      <keyboard-shortcuts></keyboard-shortcuts>
      <memory-manager></memory-manager>
      <jae-marketplace></jae-marketplace>
      <jae-context-peek></jae-context-peek>
      ${crackActive ? html`<div id="crack-overlay" class="jae-cracked-overlay" style="opacity:${crackOpacity}"></div>` : html``}
    `,
    app,
  );
}

async function initApp() {
  const app = document.getElementById("app");
  if (!app) throw new Error("App container not found");
  render(
    html`<div class="w-full h-screen flex items-center justify-center bg-background text-foreground jae-fade-in">
      <div class="flex flex-col items-center gap-3">
        <img src="/mascot/jae-default.png" class="w-16 h-16 jae-float" alt="JAE" />
        <div class="text-muted-foreground text-sm jae-shimmer" style="padding:4px 12px;border-radius:8px">Loading JAE...</div>
      </div>
    </div>`,
    app,
  );
  chatPanel = new ChatPanel();
  setupCommands();
  await refreshSidebar();
  const sessionIdFromUrl = new URLSearchParams(window.location.search).get("session");
  if (sessionIdFromUrl) {
    const loaded = await loadSession(sessionIdFromUrl);
    if (!loaded) newSession();
  } else {
    await createAgent();
  }
  renderApp();
}

initApp();
