import { useEffect, useState } from "react";
import { invoke } from "@tauri-apps/api/core";
import { open } from "@tauri-apps/plugin-dialog";
import { useToast } from "./Toast";

interface LlmConfig {
  api_url: string;
  api_key: string;
  model: string;
  temperature: number;
  max_tokens: number;
  top_p: number;
  image_model: string;
  embed_model: string;
}

interface DataDirInfo {
  current: string;
  configured: string | null;
  default: string;
}

export function SettingsPanel() {
  const [config, setConfig] = useState<LlmConfig | null>(null);
  const [loading, setLoading] = useState(false);
  const [saved, setSaved] = useState(false);
  const [showKey, setShowKey] = useState(false);
  const [error, setError] = useState("");
  const [testing, setTesting] = useState(false);
  const [conn, setConn] = useState<{ ok: boolean; models: string[]; error: string } | null>(null);
  const [dataDir, setDataDir] = useState<DataDirInfo | null>(null);
  const [relocating, setRelocating] = useState(false);
  // ponytail: advanced SQLite viewer — read-only, two DBs (lore.db / generations.db).
  const [sqlDb, setSqlDb] = useState<"lore" | "generations">("generations");
  const [sqlInput, setSqlInput] = useState("SELECT name, type FROM sqlite_master WHERE type='table' ORDER BY name");
  const [sqlResult, setSqlResult] = useState<{ columns: string[]; rows: (string | number | null)[][] } | null>(null);
  const [sqlError, setSqlError] = useState("");
  const [sqlLoading, setSqlLoading] = useState(false);
  const { addToast } = useToast();

  // ponytail: auto-load on mount so users don't see a gate before the form.
  useEffect(() => {
    (async () => {
      try {
        const c = await invoke<LlmConfig>("get_llm_config");
        setConfig(c);
      } catch (e) {
        setError(String(e));
      }
      try {
        setDataDir(await invoke<DataDirInfo>("get_data_dir"));
      } catch {
        // non-fatal — data dir control just stays hidden
      }
    })();
  }, []);

  // ponytail: pick a folder, copy existing campaign data into it, persist the
  // preference. The open SQLite connections stay on the old paths until the
  // DM restarts, so we tell them to relaunch.
  async function chooseDataDir() {
    try {
      const picked = await open({ directory: true, multiple: false, title: "Choose where DM-Pal saves campaign data" });
      if (!picked || typeof picked !== "string") return;
      setRelocating(true);
      const info = await invoke<DataDirInfo>("set_data_dir", { newDir: picked });
      setDataDir(info);
      addToast(`Campaign data will save to ${picked} — restart DM-Pal to apply. Existing data was copied there.`, "success");
    } catch (e) {
      addToast(`Couldn't set data location: ${e}`, "error");
    }
    setRelocating(false);
  }

  async function resetDataDir() {
    try {
      await invoke("reset_data_dir");
      setDataDir(await invoke<DataDirInfo>("get_data_dir"));
      addToast("Reverted to default location — restart DM-Pal to apply", "info");
    } catch (e) {
      addToast(`Couldn't reset: ${e}`, "error");
    }
  }

  // ponytail: run a read-only query against the selected DB. The backend gates
  // on SELECT/PRAGMA/WITH, so this is safe to expose in Settings.
  async function runSql() {
    setSqlLoading(true);
    setSqlError("");
    setSqlResult(null);
    try {
      const res = await invoke<{ columns: string[]; rows: (string | number | null)[][] }>("sql_query", { req: { db: sqlDb, sql: sqlInput } });
      setSqlResult(res);
      if (res.rows.length === 0) setSqlError("(0 rows)");
    } catch (e) {
      setSqlError(String(e));
    }
    setSqlLoading(false);
  }

  function quickQuery(q: string) {
    setSqlInput(q);
    // run after the state flushes
    setTimeout(runSql, 0);
  }

  function switchDb(db: "lore" | "generations") {
    setSqlDb(db);
    setSqlResult(null);
    setSqlError("");
    const q = "SELECT name, type FROM sqlite_master WHERE type='table' ORDER BY name";
    setSqlInput(q);
    // ponytail: runSql reads sqlDb from closure (stale here), so inline the
    // invoke with the new db to avoid a second render round-trip.
    setSqlLoading(true);
    invoke<{ columns: string[]; rows: (string | number | null)[][] }>("sql_query", { req: { db, sql: q } })
      .then((res) => { setSqlResult(res); if (res.rows.length === 0) setSqlError("(0 rows)"); })
      .catch((e) => setSqlError(String(e)))
      .finally(() => setSqlLoading(false));
  }

  async function saveConfig() {
    if (!config) return;
    setLoading(true);
    try {
      await invoke("set_llm_config", { config });
      setSaved(true);
      setTimeout(() => setSaved(false), 2000);
      addToast("Settings saved", "success");
    } catch (e) {
      addToast(`Save failed: ${e}`, "error");
    }
    setLoading(false);
  }

  // ponytail: probe the configured endpoint for a model list. Ollama uses
  // /api/tags, OpenAI-compatible uses /v1/models. The Rust side branches.
  async function testConnection() {
    if (!config) return;
    setTesting(true);
    setConn(null);
    try {
      // Save first so the backend uses the latest URL/key.
      await invoke("set_llm_config", { config });
      const result = await invoke<{ ok: boolean; models: string[]; error: string }>("test_connection");
      setConn(result);
      if (result.ok) addToast(`Connected — ${result.models.length} models`, "success");
      else addToast(`Connection failed: ${result.error}`, "error");
    } catch (e) {
      setConn({ ok: false, models: [], error: String(e) });
      addToast(`Connection failed: ${e}`, "error");
    }
    setTesting(false);
  }

  // ponytail: provider presets fill in the API URL pattern + default model.
  const PRESETS: { label: string; url: string; model: string; key?: boolean }[] = [
    { label: "Ollama", url: "http://localhost:11434", model: "llama3.2" },
    { label: "LM Studio", url: "http://localhost:1234/v1", model: "local-model" },
    { label: "OpenAI", url: "https://api.openai.com", model: "gpt-4o-mini", key: true },
    { label: "Custom", url: "", model: "" },
  ];
  function applyPreset(p: { url: string; model: string }) {
    if (!config) return;
    setConfig({ ...config, api_url: p.url, model: p.model });
    setConn(null);
  }

  // ponytail: reset to the backend's default config. The Rust Default impl
  // is the single source of truth; we just set an empty config and let the
  // backend re-default on save — but we can't send a partial, so mirror the
  // known defaults here and toast.
  const DEFAULTS: LlmConfig = {
    api_url: "http://localhost:11434",
    api_key: "",
    model: "llama3.2",
    temperature: 0.7,
    max_tokens: 512,
    top_p: 0.9,
    image_model: "x/flux2-klein:4b",
    embed_model: "nomic-embed-text",
  };
  function resetDefaults() {
    setConfig({ ...DEFAULTS });
    setConn(null);
    addToast("Reset to defaults — click Save to apply", "info");
  }

  // ponytail: export/import the whole config as JSON. Export downloads a file;
  // import reads a file and merges into the form (Save still required to persist).
  function exportConfig() {
    if (!config) return;
    const blob = new Blob([JSON.stringify(config, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "dm-pal-config.json";
    a.click();
    URL.revokeObjectURL(url);
    addToast("Config exported", "success");
  }

  function importConfig(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      try {
        const parsed = JSON.parse(String(reader.result)) as Partial<LlmConfig>;
        setConfig((c) => ({ ...c, ...parsed } as LlmConfig));
        setConn(null);
        addToast("Config imported — click Save to apply", "info");
      } catch {
        addToast("Invalid config file", "error");
      }
    };
    reader.readAsText(file);
    e.target.value = "";
  }

  if (!config) {
    return (
      <div className="flex flex-col items-center justify-center h-full gap-3">
        <p className="text-[var(--color-text-secondary)] text-sm">Loading settings…</p>
        {error && (
          <p className="text-[var(--color-danger)] text-xs">Failed to load: {error}</p>
        )}
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-4 text-sm">
      {/* Storage - where campaign data (lore db, generations db, generated images) lives. */}
      {dataDir ? (
        <>
          <h3 className="font-heading text-[var(--color-gold-bright)] text-xs font-semibold uppercase tracking-wider border-b border-[var(--color-border-subtle)] pb-1 mb-1">Storage</h3>
          <div className="flex flex-col gap-1">
            <label className="text-[var(--color-text-secondary)] text-xs font-medium">Campaign data location</label>
            <p className="text-[10px] text-[var(--color-text-dim)] leading-relaxed">
              Where the lore database, generations database, and generated images are saved.
            </p>
            <div className="flex items-center gap-2">
              <code className="flex-1 min-w-0 truncate rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] text-xs" title={dataDir.current}>
                {dataDir.current}
              </code>
              <button
                type="button"
                onClick={chooseDataDir}
                disabled={relocating}
                className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-secondary)] px-3 py-2 text-xs hover:border-[var(--color-gold-bright)] hover:text-[var(--color-gold-bright)] transition-colors cursor-pointer disabled:opacity-50"
              >
                {relocating ? "Moving…" : "Choose…"}
              </button>
              <button
                type="button"
                onClick={resetDataDir}
                className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-3 py-2 text-xs hover:text-[var(--color-danger)] hover:border-[var(--color-danger)] transition-colors cursor-pointer"
                title="Use the OS default location"
              >
                Reset
              </button>
            </div>
            {dataDir.configured ? (
              dataDir.configured !== dataDir.current ? (
                <div className="rounded-lg bg-[var(--color-gold-glow)] border border-[var(--color-gold-bright)]/40 px-3 py-2 text-xs text-[var(--color-gold-bright)] flex items-center justify-between gap-2">
                  <span>
                    ⏳ Pending move to <code className="font-mono">{dataDir.configured}</code> - restart DM-Pal to apply.
                  </span>
                  <button onClick={resetDataDir} className="text-[var(--color-text-dim)] hover:text-[var(--color-danger)] cursor-pointer underline" title="Cancel the pending move">
                    cancel
                  </button>
                </div>
              ) : null
            ) : null}
          </div>
        </>
      ) : null}
      <h3 className="font-heading text-[var(--color-gold-bright)] text-xs font-semibold uppercase tracking-wider border-b border-[var(--color-border-subtle)] pb-1 mb-1">LLM Connection</h3>
      {/* Provider presets */}
      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">Provider</label>
        <div className="flex flex-wrap gap-1.5">
          {PRESETS.map((p) => (
            <button
              key={p.label}
              type="button"
              onClick={() => applyPreset(p)}
              className={`rounded-lg px-2.5 py-1 text-xs border transition-colors cursor-pointer ${
                config.api_url === p.url
                  ? "bg-[var(--color-gold-glow)] border-[var(--color-gold-bright)] text-[var(--color-gold-bright)]"
                  : "bg-[var(--color-bg-surface)] border-[var(--color-border-glass)] text-[var(--color-text-dim)] hover:text-[var(--color-text-secondary)]"
              }`}
            >
              {p.label}
            </button>
          ))}
        </div>
      </div>

      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">
          API URL
        </label>
        <input
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)]"
          value={config.api_url}
          onChange={(e) => setConfig({ ...config, api_url: e.target.value })}
          placeholder="http://localhost:11434"
        />
      </div>

      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">
          API Key (optional)
        </label>
        <div className="flex gap-1.5">
          <input
            className="flex-1 rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)]"
            type={showKey ? "text" : "password"}
            value={config.api_key}
            onChange={(e) => setConfig({ ...config, api_key: e.target.value })}
            placeholder="sk-... (leave blank for local)"
          />
          <button
            type="button"
            onClick={() => setShowKey((s) => !s)}
            className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-2 text-[var(--color-text-dim)] hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] transition-colors text-xs cursor-pointer"
            title={showKey ? "Hide" : "Show"}
          >
            {showKey ? "Hide" : "Show"}
          </button>
        </div>
      </div>

      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">
          Model
        </label>
        <input
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)]"
          value={config.model}
          onChange={(e) => setConfig({ ...config, model: e.target.value })}
          placeholder="llama3.2"
          list="model-list"
        />
        <datalist id="model-list">
          {conn?.models.map((m) => (
            <option key={m} value={m} />
          ))}
        </datalist>
      </div>

      {/* Connection test */}
      <div className="flex items-center gap-2">
        <button
          type="button"
          onClick={testConnection}
          disabled={testing}
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-1.5 text-xs font-medium text-[var(--color-text-secondary)] hover:border-[var(--color-gold-bright)] hover:text-[var(--color-gold-bright)] transition-colors cursor-pointer disabled:opacity-50"
        >
          {testing ? "Testing…" : "Test connection"}
        </button>
        {conn && (
          <span className={`text-xs ${conn.ok ? "text-[var(--color-success)]" : "text-[var(--color-danger)]"}`}>
            {conn.ok ? `✓ ${conn.models.length} models` : `✕ ${conn.error}`}
          </span>
        )}
      </div>
      {conn?.ok && conn.models.length > 0 && (
        <div className="flex flex-wrap gap-1 max-h-24 overflow-y-auto">
          {conn.models.map((m) => (
            <button
              key={m}
              type="button"
              onClick={() => setConfig({ ...config, model: m })}
              className={`rounded-full px-2 py-0.5 text-[10px] border cursor-pointer transition-colors ${
                config.model === m
                  ? "bg-[var(--color-gold-glow)] border-[var(--color-gold-bright)] text-[var(--color-gold-bright)]"
                  : "bg-[var(--color-bg-deep)] border-[var(--color-border-subtle)] text-[var(--color-text-dim)] hover:text-[var(--color-text-secondary)]"
              }`}
            >
              {m}
            </button>
          ))}
        </div>
      )}

      <h3 className="font-heading text-[var(--color-gold-bright)] text-xs font-semibold uppercase tracking-wider border-b border-[var(--color-border-subtle)] pb-1 mb-1">Image Model</h3>
      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">
          Image model
        </label>
        <input
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)]"
          value={config.image_model}
          onChange={(e) => setConfig({ ...config, image_model: e.target.value })}
          placeholder="x/flux2-klein:4b"
        />
      </div>

      <h3 className="font-heading text-[var(--color-gold-bright)] text-xs font-semibold uppercase tracking-wider border-b border-[var(--color-border-subtle)] pb-1 mb-1">Embedding Model (Lore RAG)</h3>
      <div className="flex flex-col gap-1">
        <label className="text-[var(--color-text-secondary)] text-xs font-medium">
          Embedding model (Lore RAG)
        </label>
        <input
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)]"
          value={config.embed_model}
          onChange={(e) => setConfig({ ...config, embed_model: e.target.value })}
          placeholder="nomic-embed-text"
        />
      </div>

      <h3 className="font-heading text-[var(--color-gold-bright)] text-xs font-semibold uppercase tracking-wider border-b border-[var(--color-border-subtle)] pb-1 mb-1">Text Model</h3>
      <div className="grid grid-cols-2 gap-3">
        <div className="flex flex-col gap-1">
          <label className="text-[var(--color-text-secondary)] text-xs font-medium">
            Temperature: {config.temperature}
          </label>
          <input
            type="range"
            min="0"
            max="2"
            step="0.1"
            value={config.temperature}
            onChange={(e) =>
              setConfig({ ...config, temperature: parseFloat(e.target.value) })
            }
            className="accent-[var(--color-gold-bright)]"
          />
        </div>
        <div className="flex flex-col gap-1">
          <label className="text-[var(--color-text-secondary)] text-xs font-medium">
            Max Tokens: {config.max_tokens}
          </label>
          <input
            type="range"
            min="64"
            max="4096"
            step="64"
            value={config.max_tokens}
            onChange={(e) =>
              setConfig({ ...config, max_tokens: parseInt(e.target.value) })
            }
            className="accent-[var(--color-gold-bright)]"
          />
        </div>
      </div>

      <div className="flex flex-wrap gap-2">
        <button
          onClick={saveConfig}
          disabled={loading}
          className="rounded-lg bg-[var(--color-gold-bright)] text-[var(--color-bg-deep)] px-4 py-2 text-sm font-semibold hover:bg-[var(--color-gold-muted)] transition-colors cursor-pointer disabled:opacity-50"
        >
          {saved ? "✓ Saved" : loading ? "Saving…" : "Save Settings"}
        </button>
        <button
          onClick={resetDefaults}
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-4 py-2 text-sm hover:text-[var(--color-danger)] hover:border-[var(--color-danger)] transition-colors cursor-pointer"
        >
          Reset to defaults
        </button>
        <button
          onClick={exportConfig}
          className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-4 py-2 text-sm hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] transition-colors cursor-pointer"
        >
          ⬆ Export
        </button>
        <label className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-4 py-2 text-sm hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] transition-colors cursor-pointer flex items-center">
          ⬇ Import
          <input
            type="file"
            accept="application/json,.json"
            className="hidden"
            onChange={importConfig}
          />
        </label>
      </div>

      {/* Advanced — read-only SQLite viewer for inspecting the backend DBs. */}
      <details
        className="rounded-lg border border-[var(--color-border-subtle)] bg-[var(--color-bg-deep)]"
        onToggle={(e) => { if ((e.target as HTMLDetailsElement).open && !sqlResult && !sqlLoading) runSql(); }}
      >
        <summary className="px-3 py-2 text-xs font-medium text-[var(--color-text-dim)] cursor-pointer hover:text-[var(--color-text-secondary)] select-none">
          Advanced · SQLite viewer
        </summary>
        <div className="p-3 flex flex-col gap-2 border-t border-[var(--color-border-subtle)]">
          <p className="text-[10px] text-[var(--color-text-dim)] leading-relaxed">
            Read-only inspection of the local databases (lore.db, generations.db). Only SELECT / PRAGMA / WITH statements run. Embedding vectors show as <code>&lt;blob N bytes&gt;</code>.
          </p>
          <div className="flex items-center gap-2 flex-wrap">
            <select
              value={sqlDb}
              onChange={(e) => switchDb(e.target.value as "lore" | "generations")}
              className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-2 py-1.5 text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-gold-bright)] text-xs cursor-pointer"
              aria-label="Database"
            >
              <option value="generations">Generations DB</option>
              <option value="lore">Lore DB</option>
            </select>
            <button onClick={() => quickQuery("SELECT name, type FROM sqlite_master WHERE type='table' ORDER BY name")} className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-2.5 py-1.5 text-[10px] hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] cursor-pointer">Tables</button>
            <button onClick={() => quickQuery(sqlDb === "lore" ? "PRAGMA table_info(chunks)" : "PRAGMA table_info(generations)")} className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-2.5 py-1.5 text-[10px] hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] cursor-pointer">Schema</button>
            <button onClick={() => quickQuery(sqlDb === "lore" ? "SELECT id, source, substr(text,1,80) AS preview FROM chunks ORDER BY id DESC LIMIT 25" : "SELECT * FROM generations ORDER BY created_at DESC LIMIT 25")} className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-2.5 py-1.5 text-[10px] hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] cursor-pointer">Browse</button>
            <button onClick={() => quickQuery(sqlDb === "lore" ? "SELECT source, COUNT(*) AS chunks FROM chunks GROUP BY source ORDER BY chunks DESC" : "SELECT kind, COUNT(*) AS n FROM generations GROUP BY kind")} className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] text-[var(--color-text-dim)] px-2.5 py-1.5 text-[10px] hover:text-[var(--color-gold-bright)] hover:border-[var(--color-gold-bright)] cursor-pointer">Count</button>
          </div>
          <textarea
            className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)] text-xs font-mono min-h-20 resize-y"
            value={sqlInput}
            onChange={(e) => setSqlInput(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && (e.metaKey || e.ctrlKey) && runSql()}
            spellCheck={false}
            placeholder="SELECT * FROM … (⌘Enter to run)"
          />
          <div className="flex items-center gap-2">
            <button
              onClick={runSql}
              disabled={sqlLoading}
              className="rounded-lg bg-[var(--color-gold-bright)] text-[var(--color-bg-deep)] px-3 py-1.5 text-xs font-semibold hover:bg-[var(--color-gold-muted)] transition-colors cursor-pointer disabled:opacity-50"
            >
              {sqlLoading ? "Running…" : "Run query"}
            </button>
            <span className="text-[10px] text-[var(--color-text-dim)]">⌘Enter to run · read-only</span>
          </div>

          {sqlError ? (
            <p className="text-[10px] text-[var(--color-danger)] font-mono whitespace-pre-wrap">{sqlError}</p>
          ) : null}

          {sqlResult ? (
            <div className="rounded-lg border border-[var(--color-border-subtle)] overflow-hidden">
              <div className="max-h-72 overflow-auto">
                <table className="w-full text-[10px] font-mono">
                  <thead className="sticky top-0 bg-[var(--color-bg-surface)]">
                    <tr>
                      {sqlResult.columns.map((c) => <th key={c} className="text-left text-[var(--color-gold-bright)] px-2 py-1 border-b border-[var(--color-border-subtle)] whitespace-nowrap">{c}</th>)}
                    </tr>
                  </thead>
                  <tbody>
                    {sqlResult.rows.map((row, i) => (
                      <tr key={i} className="odd:bg-[var(--color-bg-surface)]/30">
                        {row.map((cell, j) => <td key={j} className="px-2 py-1 text-[var(--color-text-secondary)] max-w-64 truncate" title={String(cell)}>{cell === null ? <span className="text-[var(--color-text-dim)]">NULL</span> : String(cell)}</td>)}
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <div className="px-2 py-1 text-[10px] text-[var(--color-text-dim)] border-t border-[var(--color-border-subtle)]">
                {sqlResult.rows.length} row{sqlResult.rows.length === 1 ? "" : "s"}
              </div>
            </div>
          ) : null}
        </div>
      </details>
    </div>
  );
}