import { useState, useRef, useCallback, useEffect } from "react";
import { PanelGroup, Panel, PanelResizeHandle } from "react-resizable-panels";
import { Play, Loader2, BookOpen, Zap, Database } from "lucide-react";
import { toast } from "sonner";
import { Link } from "wouter";
import { api, type LintResult, type ParseResult, type FormatResult, type InjectionResult, type HealthResult } from "@/lib/api";
import { SqlEditor } from "@/components/SqlEditor";
import { AstTreeView } from "@/components/AstTreeView";
import { LintPanel } from "@/components/LintPanel";
import { InjectionPanel } from "@/components/InjectionPanel";
import { FormatterPanel } from "@/components/FormatterPanel";

// ── Constants ──────────────────────────────────────────────────────────────

type AnalysisTab = "ast" | "lint" | "injection" | "formatted";

const TABS: { id: AnalysisTab; label: string }[] = [
  { id: "ast",       label: "AST Tree"  },
  { id: "lint",      label: "Lint"      },
  { id: "injection", label: "Injection" },
  { id: "formatted", label: "Formatted" },
];

const DIALECTS = [
  { value: "ansi",       label: "ANSI SQL"    },
  { value: "postgres",   label: "PostgreSQL"  },
  { value: "mysql",      label: "MySQL"       },
  { value: "tsql",       label: "T-SQL"       },
  { value: "sqlite",     label: "SQLite"      },
  { value: "bigquery",   label: "BigQuery"    },
  { value: "snowflake",  label: "Snowflake"   },
  { value: "redshift",   label: "Redshift"    },
  { value: "duckdb",     label: "DuckDB"      },
  { value: "hive",       label: "Hive"        },
  { value: "sparksql",   label: "Spark SQL"   },
  { value: "trino",      label: "Trino"       },
  { value: "databricks", label: "Databricks"  },
  { value: "oracle",     label: "Oracle"      },
  { value: "teradata",   label: "Teradata"    },
  { value: "clickhouse", label: "ClickHouse"  },
  { value: "athena",     label: "Athena"      },
];

const DEFAULT_SQL = `-- SQL Analyzer Demo
-- Press Ctrl+Enter (or Cmd+Enter) to analyze

SELECT
    u.id,
    u.name,
    u.email,
    o.total,
    o.created_at
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE u.active = 1
    AND o.created_at >= '2024-01-01'
ORDER BY o.created_at DESC
LIMIT 50;`;

const INJECTION_SQL = `-- SQL Injection Demo
-- This query contains several injection patterns

SELECT * FROM users
WHERE username = 'admin' OR 1=1 --
AND password = 'anything';

-- Stacked query attempt
SELECT * FROM products WHERE id = 1;
DROP TABLE users;

-- UNION-based exfiltration
SELECT id, name FROM products
UNION SELECT username, password FROM users;`;

// ── Status indicator ───────────────────────────────────────────────────────

function StatusDot({ health }: { health: HealthResult | null }) {
  const isOk = health?.status === "ok";
  return (
    <div className="flex items-center gap-1.5">
      <div
        className={`w-1.5 h-1.5 rounded-full ${isOk ? "animate-pulse" : ""}`}
        style={{ background: isOk ? "var(--accent-green)" : "var(--accent-yellow)" }}
      />
      <span className="text-[10px]" style={{ color: "var(--text-muted)", fontFamily: "var(--font-mono)" }}>
        {isOk ? `SQLFluff ${health!.version}` : "starting…"}
      </span>
    </div>
  );
}

// ── Main page ──────────────────────────────────────────────────────────────

export default function Analyzer() {
  const [sql, setSql] = useState(DEFAULT_SQL);
  const [dialect, setDialect] = useState("ansi");
  const [activeTab, setActiveTab] = useState<AnalysisTab>("ast");
  const [isAnalyzing, setIsAnalyzing] = useState(false);

  const [health, setHealth] = useState<HealthResult | null>(null);
  const [lintResult, setLintResult] = useState<LintResult | null>(null);
  const [parseResult, setParseResult] = useState<ParseResult | null>(null);
  const [formatResult, setFormatResult] = useState<FormatResult | null>(null);
  const [injectResult, setInjectResult] = useState<InjectionResult | null>(null);
  const [analysisTime, setAnalysisTime] = useState<number | null>(null);

  const editorContainerRef = useRef<HTMLDivElement>(null);

  // Poll health endpoint every 6 s until ready
  useEffect(() => {
    let cancelled = false;
    async function poll() {
      try {
        const h = await api.health();
        if (!cancelled) setHealth(h);
      } catch {
        // still starting
      }
    }
    poll();
    const id = setInterval(poll, 6000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  // ── Analyze ────────────────────────────────────────────────────────────

  const handleAnalyze = useCallback(async () => {
    if (!sql.trim()) { toast.error("Please enter some SQL to analyze"); return; }
    if (health?.status !== "ok") { toast.error("API is not ready yet — please wait a moment"); return; }

    setIsAnalyzing(true);
    const start = Date.now();

    try {
      const [lint, parse, format, inject] = await Promise.allSettled([
        api.lint(sql, dialect),
        api.parse(sql, dialect),
        api.format(sql, dialect),
        api.inject(sql, dialect),
      ]);

      if (lint.status   === "fulfilled") setLintResult(lint.value);
      if (parse.status  === "fulfilled") setParseResult(parse.value);
      if (format.status === "fulfilled") setFormatResult(format.value);
      if (inject.status === "fulfilled") setInjectResult(inject.value);

      setAnalysisTime(Date.now() - start);

      const lv = lint.status   === "fulfilled" ? lint.value   : null;
      const iv = inject.status === "fulfilled" ? inject.value : null;
      if (lv && iv) {
        if (!lv.passed || !iv.safe) {
          toast.warning(
            `Analysis complete — ${lv.stats.total} lint issue${lv.stats.total !== 1 ? "s" : ""}${!iv.safe ? `, risk score ${iv.risk_score}/100` : ""}`,
            { duration: 4000 }
          );
        } else {
          toast.success("Analysis complete — no issues found", { duration: 3000 });
        }
      }
    } catch (err) {
      toast.error((err instanceof Error ? err.message : "Analysis failed").slice(0, 120));
    } finally {
      setIsAnalyzing(false);
    }
  }, [sql, dialect, health]);

  // ── Jump to line ───────────────────────────────────────────────────────

  const jumpToLine = useCallback((lineNo: number) => {
    const container = editorContainerRef.current;
    if (!container) return;
    const editorEl = container.querySelector("[data-editor-container]");
    if (!editorEl) return;
    editorEl.dispatchEvent(new CustomEvent("jump-to-line", { detail: lineNo }));
  }, []);

  const lintBadge   = lintResult   && !lintResult.passed   ? lintResult.stats.total        : null;
  const injectBadge = injectResult && !injectResult.safe    ? injectResult.patterns.length  : null;

  // ── Render ─────────────────────────────────────────────────────────────

  return (
    <div className="flex flex-col h-screen" style={{ background: "var(--bg-base)", color: "var(--text-primary)" }}>
      {/* Header */}
      <header
        className="flex items-center gap-3 px-4 py-2.5 flex-shrink-0"
        style={{ borderBottom: "1px solid var(--border)", background: "var(--bg-surface)" }}
      >
        {/* Logo */}
        <div className="flex items-center gap-2 mr-2">
          <div
            className="w-7 h-7 rounded flex items-center justify-center"
            style={{ background: "rgba(88,166,255,0.12)", border: "1px solid rgba(88,166,255,0.25)" }}
          >
            <Database size={14} style={{ color: "var(--accent-blue)" }} />
          </div>
          <span className="text-sm font-semibold tracking-tight">SQL Analyzer</span>
        </div>

        {/* Dialect selector */}
        <select
          value={dialect}
          onChange={(e) => setDialect(e.target.value)}
          className="h-7 text-xs rounded px-2 pr-6 appearance-none cursor-pointer"
          style={{
            background: "var(--bg-elevated)",
            border: "1px solid var(--border)",
            color: "var(--text-primary)",
            fontFamily: "var(--font-mono)",
            outline: "none",
          }}
        >
          {DIALECTS.map((d) => (
            <option key={d.value} value={d.value}>{d.label}</option>
          ))}
        </select>

        {/* Example loader */}
        <select
          defaultValue=""
          onChange={(e) => {
            if (e.target.value === "demo") setSql(DEFAULT_SQL);
            else if (e.target.value === "injection") setSql(INJECTION_SQL);
            e.target.value = "";
          }}
          className="h-7 text-xs rounded px-2 pr-6 appearance-none cursor-pointer"
          style={{
            background: "var(--bg-elevated)",
            border: "1px solid var(--border)",
            color: "var(--text-secondary)",
            outline: "none",
          }}
        >
          <option value="" disabled>Examples…</option>
          <option value="demo">Demo Query</option>
          <option value="injection">Injection Demo</option>
        </select>

        <div className="flex-1" />

        <StatusDot health={health} />

        {analysisTime !== null && (
          <span className="text-[10px]" style={{ color: "var(--text-muted)", fontFamily: "var(--font-mono)" }}>
            {analysisTime}ms
          </span>
        )}

        {/* API Docs link */}
        <Link href="/swagger">
          <button
            className="flex items-center gap-1.5 h-7 px-2 text-xs rounded transition-colors"
            style={{ color: "var(--text-secondary)" }}
            onMouseEnter={(e) => (e.currentTarget.style.color = "var(--text-primary)")}
            onMouseLeave={(e) => (e.currentTarget.style.color = "var(--text-secondary)")}
          >
            <BookOpen size={11} />
            API Docs
          </button>
        </Link>

        {/* Analyze button */}
        <button
          onClick={handleAnalyze}
          disabled={isAnalyzing || health?.status !== "ok"}
          className="flex items-center gap-1.5 h-7 px-3 text-xs font-semibold rounded transition-opacity disabled:opacity-40"
          style={{ background: "var(--accent-blue)", color: "var(--bg-base)" }}
        >
          {isAnalyzing ? <Loader2 size={12} className="animate-spin" /> : <Play size={11} />}
          {isAnalyzing ? "Analyzing…" : "Analyze"}
          <span className="text-[9px] opacity-60 ml-0.5">⌘↵</span>
        </button>
      </header>

      {/* Split panels */}
      <div className="flex-1 overflow-hidden">
        <PanelGroup direction="horizontal" className="h-full">
          {/* Left: SQL Editor */}
          <Panel defaultSize={50} minSize={20}>
            <div className="flex flex-col h-full">
              <div
                className="flex items-center gap-2 px-3 py-1.5 flex-shrink-0"
                style={{ borderBottom: "1px solid var(--border-muted)" }}
              >
                <span className="text-[10px]" style={{ color: "var(--text-muted)", fontFamily: "var(--font-mono)" }}>
                  SQL Editor
                </span>
                <span className="ml-auto text-[10px]" style={{ color: "var(--text-muted)", fontFamily: "var(--font-mono)" }}>
                  Ctrl+Enter to analyze
                </span>
              </div>
              <div ref={editorContainerRef} className="flex-1 overflow-hidden">
                <SqlEditor value={sql} onChange={setSql} onAnalyze={handleAnalyze} dialect={dialect} />
              </div>
            </div>
          </Panel>

          {/* Resize handle */}
          <PanelResizeHandle
            className="w-1 cursor-col-resize transition-colors"
            style={{ background: "var(--border)" }}
          />

          {/* Right: Results */}
          <Panel defaultSize={50} minSize={20}>
            <div className="flex flex-col h-full">
              {/* Tab bar */}
              <div
                className="flex items-center flex-shrink-0 px-1"
                style={{ borderBottom: "1px solid var(--border)" }}
              >
                {TABS.map((tab) => {
                  const badge = tab.id === "lint" ? lintBadge : tab.id === "injection" ? injectBadge : null;
                  const isActive = activeTab === tab.id;
                  return (
                    <button
                      key={tab.id}
                      onClick={() => setActiveTab(tab.id)}
                      className="relative flex items-center gap-1.5 px-3 py-2 text-xs font-medium transition-colors border-b-2"
                      style={{
                        color: isActive ? "var(--accent-blue)" : "var(--text-secondary)",
                        borderBottomColor: isActive ? "var(--accent-blue)" : "transparent",
                      }}
                    >
                      {tab.label}
                      {badge !== null && (
                        <span
                          className="text-[9px] font-bold px-1 py-0.5 rounded-full min-w-[16px] text-center"
                          style={{ background: "rgba(255,123,114,0.2)", color: "var(--accent-red)" }}
                        >
                          {badge}
                        </span>
                      )}
                    </button>
                  );
                })}
              </div>

              {/* Tab content */}
              <div className="flex-1 overflow-hidden">
                {activeTab === "ast" && (
                  <AstTreeView
                    tree={parseResult?.tree ?? null}
                    tokenCount={parseResult?.token_count}
                    depth={parseResult?.depth}
                    onJumpToLine={jumpToLine}
                  />
                )}
                {activeTab === "lint" && (
                  <LintPanel result={lintResult} onJumpToLine={jumpToLine} />
                )}
                {activeTab === "injection" && (
                  <InjectionPanel result={injectResult} onJumpToLine={jumpToLine} />
                )}
                {activeTab === "formatted" && (
                  <FormatterPanel result={formatResult} onApplyToEditor={setSql} />
                )}
              </div>
            </div>
          </Panel>
        </PanelGroup>
      </div>
    </div>
  );
}
