/**
 * DBBrowserPanel.tsx — S746: Integrated DB browser in-app (Gap 6 IDE Analysis)
 *
 * Esplora le table Dexie (IndexedDB) dal device:
 * - Conteggio record per table + preview ultimi 5
 * - Export tabella come JSON (download)
 * - Clear tabella (con conferma)
 * - Quota storage totale (navigator.storage.estimate)
 *
 * Sprint: S746 — Gap 6 IDE Analysis (Integrated DB — database browser in-app)
 */

import { useState, useEffect, useCallback, memo } from "react";
import type * as React from "react";
import { X, Database, RefreshCw, Download, Trash2, ChevronDown, ChevronRight, AlertCircle } from "lucide-react";
import { Z_INDEX } from "@/lib/zindex";
import { vfsDb } from "@/lib/vfsDb";
import type { Table } from "dexie";

interface DBBrowserPanelProps { onClose: () => void; }

interface TableInfo {
  name:    string;
  label:   string;
  count:   number | null;
  preview: unknown[];
  loading: boolean;
  open:    boolean;
  error?:  string;
}

// ─── Table definitions ────────────────────────────────────────────────────────
const TABLES: Array<{ name: string; label: string; key: keyof typeof vfsDb }> = [
  { name: "files",        label: "📁 File VFS",         key: "files" },
  { name: "messages",     label: "💬 Messaggi",          key: "messages" },
  { name: "conversations",label: "🗂 Conversazioni",     key: "conversations" },
  { name: "tasks",        label: "⚙️ Task agente",       key: "tasks" },
  { name: "snapshots",    label: "📸 Snapshot",          key: "snapshots" },
  { name: "agentMemory",  label: "🧠 Memoria agente",    key: "agentMemory" },
  { name: "agentContext", label: "📋 Contesto agente",   key: "agentContext" },
  { name: "skillUsage",   label: "🔧 Skill usage",       key: "skillUsage" },
  { name: "telemetry",    label: "📊 Telemetria",        key: "telemetry" },
  { name: "diagnosticsLog",label: "🔴 Diagnostics log",  key: "diagnosticsLog" },
  { name: "runtimeEvents",label: "⚡ Runtime events",    key: "runtimeEvents" },
  { name: "providerUsage",label: "🔑 Provider usage",    key: "providerUsage" },
  { name: "sessions",     label: "📂 Sessioni",          key: "sessions" },
  { name: "fileBackups",  label: "💾 File backups",      key: "fileBackups" },
];

// ─── Typed table accessor (avoids `as any` on dynamic Dexie table lookup) ────
type VfsTable = Table<unknown, unknown>;

function getTable(name: string): VfsTable | undefined {
  const entry = TABLES.find(t => t.name === name);
  return entry ? (vfsDb[entry.key] as unknown as VfsTable) : undefined;
}

// ─── Helpers ──────────────────────────────────────────────────────────────────
function formatBytes(b: number): string {
  if (b < 1024)        return `${b} B`;
  if (b < 1_048_576)  return `${(b / 1024).toFixed(1)} KB`;
  return `${(b / 1_048_576).toFixed(2)} MB`;
}

function previewValue(v: unknown, depth = 0): string {
  if (v === null || v === undefined) return String(v);
  if (typeof v === "string") return v.length > 80 ? v.slice(0, 80) + "…" : v;
  if (typeof v === "number" || typeof v === "boolean") return String(v);
  if (Array.isArray(v)) return `[${v.length} items]`;
  if (typeof v === "object" && depth < 2) {
    const entries = Object.entries(v as Record<string, unknown>).slice(0, 3);
    return "{" + entries.map(([k, val]) => `${k}: ${previewValue(val, depth + 1)}`).join(", ") + (Object.keys(v as object).length > 3 ? ", …" : "") + "}";
  }
  return "[object]";
}

async function exportTable(tableName: string): Promise<void> {
  const table = getTable(tableName);
  if (!table) return;
  const data = await table.toArray();
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
  const url  = URL.createObjectURL(blob);
  const a    = document.createElement("a");
  a.href     = url;
  a.download = `${tableName}-${new Date().toISOString().slice(0,10)}.json`;
  a.click();
  URL.revokeObjectURL(url);
}

// ─── Stili ────────────────────────────────────────────────────────────────────
const iconBtn = (color = "#6366f1"): React.CSSProperties => ({
  all: "unset" as const, cursor: "pointer", color, padding: "4px 6px",
  borderRadius: 8, display: "flex", alignItems: "center", touchAction: "manipulation",
  transition: "background 0.15s",
});

// ─── Componente principale ─────────────────────────────────────────────────────
const DBBrowserPanel = memo(function DBBrowserPanel({ onClose }: DBBrowserPanelProps) {
  const [tables, setTables]     = useState<TableInfo[]>(
    TABLES.map(t => ({ name: t.name, label: t.label, count: null, preview: [], loading: false, open: false }))
  );
  const [totalCounts, setTotalCounts] = useState<Record<string, number>>({});
  const [quota, setQuota]       = useState<{ usedMB: number; quotaMB: number; pct: number } | null>(null);
  const [loadingAll, setLoadingAll] = useState(false);
  const [confirmClear, setConfirmClear] = useState<string | null>(null);

  // ── Carica conteggi ──────────────────────────────────────────────────────
  const loadCounts = useCallback(async () => {
    setLoadingAll(true);
    const counts: Record<string, number> = {};
    await Promise.all(TABLES.map(async t => {
      try {
        const table = getTable(t.name);
        if (table) counts[t.name] = await table.count();
      } catch { counts[t.name] = -1; }
    }));
    setTotalCounts(counts);
    setTables(prev => prev.map(t => ({ ...t, count: counts[t.name] ?? null })));
    setLoadingAll(false);

    // Quota storage
    if (navigator.storage?.estimate) {
      try {
        const { usage = 0, quota: q = 0 } = await navigator.storage.estimate();
        setQuota({ usedMB: usage / 1_048_576, quotaMB: q / 1_048_576, pct: q > 0 ? (usage / q) * 100 : 0 });
      } catch { /**/ }
    }
  }, []);

  useEffect(() => { void loadCounts(); }, [loadCounts]);

  // ── Toggle table expansion ─────────────────────────────────────────────
  const toggleTable = useCallback(async (tableName: string) => {
    setTables(prev => prev.map(t => {
      if (t.name !== tableName) return t;
      if (t.open) return { ...t, open: false };
      return { ...t, open: true, loading: true };
    }));

    try {
      const table = getTable(tableName);
      const preview = table ? await table.orderBy(":id").reverse().limit(5).toArray() : [];
      setTables(prev => prev.map(t => t.name === tableName ? { ...t, loading: false, preview } : t));
    } catch (e) {
      setTables(prev => prev.map(t => t.name === tableName ? { ...t, loading: false, error: (e as Error).message } : t));
    }
  }, []);

  // ── Clear table ──────────────────────────────────────────────────────────
  const clearTable = useCallback(async (tableName: string) => {
    try {
      const table = getTable(tableName);
      if (table) await table.clear();
      setConfirmClear(null);
      await loadCounts();
    } catch (e) {
      console.error("Clear failed:", e);
    }
  }, [loadCounts]);

  const totalRecords = Object.values(totalCounts).reduce((s, n) => s + (n > 0 ? n : 0), 0);

  return (
    <div role="dialog" aria-modal="true" aria-label="Database"
      style={{ position: "fixed", inset: 0, zIndex: Z_INDEX.MODAL, display: "flex", justifyContent: "flex-end" }}>
      <div onClick={onClose} style={{ flex: 1, background: "rgba(0,0,0,0.45)" }} />
      <div style={{
        width: "min(100vw, 420px)", height: "100%", overflowY: "auto",
        background: "rgba(6,6,18,0.97)", borderLeft: "1px solid rgba(99,102,241,0.18)",
        display: "flex", flexDirection: "column",
        paddingBottom: "env(safe-area-inset-bottom, 0px)",
      }}>
        {/* Header */}
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "14px 16px", borderBottom: "1px solid rgba(99,102,241,0.12)", flexShrink: 0 }}>
          <Database size={18} color="#6366f1" />
          <div style={{ flex: 1 }}>
            <span style={{ fontWeight: 700, fontSize: "0.95rem", color: "#d0d0f0" }}>Database (IndexedDB)</span>
            <span style={{ marginLeft: 8, fontSize: "0.7rem", color: "#4a4a78" }}>{totalRecords.toLocaleString()} record</span>
          </div>
          <button onClick={() => void loadCounts()} disabled={loadingAll}
            style={{ ...iconBtn(), opacity: loadingAll ? 0.5 : 1 }}>
            <RefreshCw size={15} style={{ animation: loadingAll ? "spin 1s linear infinite" : "none" }} />
          </button>
          <button onClick={onClose} style={iconBtn("#4a4a78")}><X size={18} /></button>
        </div>

        {/* Storage quota */}
        {quota && (
          <div style={{ padding: "10px 16px", borderBottom: "1px solid rgba(99,102,241,0.08)", display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ flex: 1 }}>
              <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
                <span style={{ fontSize: "0.7rem", color: "#4a4a78" }}>Storage quota</span>
                <span style={{ fontSize: "0.7rem", color: quota.pct > 80 ? "#f87171" : "#4a4a78" }}>
                  {formatBytes(quota.usedMB * 1_048_576)} / {formatBytes(quota.quotaMB * 1_048_576)} ({quota.pct.toFixed(1)}%)
                </span>
              </div>
              <div style={{ height: 4, background: "rgba(255,255,255,0.06)", borderRadius: 2, overflow: "hidden" }}>
                <div style={{ height: "100%", width: `${Math.min(100, quota.pct)}%`, background: quota.pct > 80 ? "#f87171" : quota.pct > 60 ? "#fbbf24" : "#6366f1", borderRadius: 2, transition: "width 0.3s" }} />
              </div>
            </div>
          </div>
        )}

        {/* Confirm clear modal */}
        {confirmClear && (
          <div style={{ margin: "10px 16px 0", padding: "12px 14px", background: "rgba(239,68,68,0.10)", border: "1px solid rgba(239,68,68,0.28)", borderRadius: 10 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 10 }}>
              <AlertCircle size={15} color="#f87171" />
              <span style={{ fontSize: "0.8rem", color: "#f87171", fontWeight: 600 }}>
                Eliminare tutti i record di &quot;{confirmClear}&quot;?
              </span>
            </div>
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <button onClick={() => setConfirmClear(null)} style={{ all: "unset", cursor: "pointer", padding: "6px 14px", borderRadius: 7, background: "rgba(255,255,255,0.06)", color: "#a0a0c0", fontSize: "0.78rem", touchAction: "manipulation" }}>Annulla</button>
              <button onClick={() => void clearTable(confirmClear)} style={{ all: "unset", cursor: "pointer", padding: "6px 14px", borderRadius: 7, background: "rgba(239,68,68,0.20)", color: "#f87171", fontSize: "0.78rem", fontWeight: 700, touchAction: "manipulation" }}>Elimina</button>
            </div>
          </div>
        )}

        {/* Tables list */}
        <div style={{ flex: 1, overflowY: "auto", padding: "10px 16px", display: "flex", flexDirection: "column", gap: 4 }}>
          {tables.map(t => (
            <div key={t.name} style={{ border: "1px solid rgba(99,102,241,0.12)", borderRadius: 10, overflow: "hidden" }}>
              {/* Table header */}
              <div
                style={{ display: "flex", alignItems: "center", gap: 8, padding: "10px 12px", cursor: "pointer", background: t.open ? "rgba(99,102,241,0.06)" : "transparent", transition: "background 0.15s", userSelect: "none", WebkitUserSelect: "none" as React.CSSProperties["WebkitUserSelect"] }}
                onClick={() => void toggleTable(t.name)}
              >
                {t.open ? <ChevronDown size={13} color="#6366f1" /> : <ChevronRight size={13} color="#4a4a78" />}
                <span style={{ flex: 1, fontSize: "0.82rem", color: "#c0c0e0" }}>{t.label}</span>
                <span style={{ fontSize: "0.7rem", color: t.count === 0 ? "#3a3a6a" : "#6366f1", background: "rgba(99,102,241,0.10)", padding: "1px 8px", borderRadius: 10, fontWeight: 600 }}>
                  {t.count === null ? "…" : t.count === -1 ? "err" : t.count.toLocaleString()}
                </span>
                <button onClick={e => { e.stopPropagation(); void exportTable(t.name); }} style={{ ...iconBtn("#4a4a78"), padding: "2px 4px" }} title="Esporta JSON">
                  <Download size={12} />
                </button>
                <button onClick={e => { e.stopPropagation(); setConfirmClear(t.name); }} style={{ ...iconBtn("#f87171"), padding: "2px 4px" }} title="Svuota tabella">
                  <Trash2 size={12} />
                </button>
              </div>

              {/* Expanded records */}
              {t.open && (
                <div style={{ borderTop: "1px solid rgba(99,102,241,0.08)", padding: "8px 12px" }}>
                  {t.loading && <p style={{ margin: 0, fontSize: "0.75rem", color: "#4a4a78" }}>⏳ Caricamento…</p>}
                  {t.error && <p style={{ margin: 0, fontSize: "0.75rem", color: "#f87171" }}>{t.error}</p>}
                  {!t.loading && t.preview.length === 0 && <p style={{ margin: 0, fontSize: "0.75rem", color: "#3a3a6a" }}>Tabella vuota.</p>}
                  {t.preview.map((row, i) => (
                    <div key={i} style={{ padding: "6px 8px", marginBottom: 4, background: "rgba(255,255,255,0.02)", borderRadius: 8, borderLeft: "2px solid rgba(99,102,241,0.25)" }}>
                      {typeof row === "object" && row !== null
                        ? Object.entries(row as Record<string, unknown>).slice(0, 5).map(([k, v]) => (
                          <div key={k} style={{ display: "flex", gap: 6, marginBottom: 2 }}>
                            <code style={{ fontSize: "0.65rem", color: "#6366f1", flexShrink: 0, minWidth: 60, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{k}</code>
                            <span style={{ fontSize: "0.65rem", color: "#7a7ab0", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>{previewValue(v)}</span>
                          </div>
                        ))
                        : <code style={{ fontSize: "0.65rem", color: "#7a7ab0" }}>{previewValue(row)}</code>
                      }
                    </div>
                  ))}
                  {t.count !== null && t.count > 5 && (
                    <p style={{ margin: "4px 0 0", fontSize: "0.65rem", color: "#3a3a6a", textAlign: "right" }}>
                      + {(t.count - 5).toLocaleString()} altri record — usa Export per vedere tutto
                    </p>
                  )}
                </div>
              )}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
});

export default DBBrowserPanel;
