import { useState, useEffect, memo, useMemo } from "react";
import { haptic } from "@/lib/haptic";
import { Copy, Check, ChevronDown, ChevronRight } from "lucide-react";
import CodeRunner from "./CodeRunner";

// ── Shiki: syntax highlight via esm.sh CDN (zero bundle impact) ───────────────
// Sostituisce highlight.js (969KB chunk) con Shiki (~200KB, tree-shakeable).
// Shiki usa inline color styles — nessun CSS esterno necessario.
// Singleton: il highlighter viene creato una sola volta e riusato per tutti i blocchi.
const _SHIKI_ESM = "https://esm.sh/shiki@1.29.2?target=es2020";
const _SHIKI_THEME = "one-dark-pro";
const _SHIKI_LANGS = [
  "javascript", "typescript", "jsx", "tsx",
  "python", "html", "css", "json", "bash", "shell",
  "markdown", "yaml", "sql", "rust", "go",
  "java", "cpp", "c", "kotlin", "swift", "php",
  "ruby", "text",
];
// Alias: identifiers usati nel progetto → nomi Shiki canonici
const _SHIKI_ALIAS: Record<string, string> = {
  js: "javascript", ts: "typescript",
  sh: "bash", py: "python",
  md: "markdown", rs: "rust",
  rb: "ruby", kt: "kotlin", yml: "yaml",
  toml: "text", xml: "text",
};

let _shikiP: Promise<any> | null = null;
function _getShiki(): Promise<any> {
  if (!_shikiP) {
    _shikiP = (async () => {
      const { createHighlighter } = await import(_SHIKI_ESM as any);
      return createHighlighter({ themes: [_SHIKI_THEME], langs: _SHIKI_LANGS });
    })().catch(() => null); // null = fallback a plain text
  }
  return _shikiP!;
}

/** Estrae l'innerHTML del <code> dal HTML prodotto da Shiki. */
function _extractCode(shikiHtml: string): string {
  const m = shikiHtml.match(/<code[^>]*>([\s\S]*?)<\/code>/);
  return m ? m[1] : shikiHtml;
}

interface CodeBlockProps {
  code: string;
  language?: string;
  onExecuteResult?: (result: string) => void;
}

// ── S56: Lang metadata con colori per categoria ──────────────────────────
const LANG_META: Record<string, { label: string; color: string }> = {
  js:         { label: "JavaScript", color: "#f7df1e" },
  javascript: { label: "JavaScript", color: "#f7df1e" },
  jsx:        { label: "JSX",        color: "#61dafb" },
  ts:         { label: "TypeScript", color: "#3178c6" },
  typescript: { label: "TypeScript", color: "#3178c6" },
  tsx:        { label: "TSX",        color: "#3178c6" },
  py:         { label: "Python",     color: "#3572a5" },
  python:     { label: "Python",     color: "#3572a5" },
  sh:         { label: "Shell",      color: "#4ec9b0" },
  bash:       { label: "Bash",       color: "#4ec9b0" },
  css:        { label: "CSS",        color: "#264de4" },
  html:       { label: "HTML",       color: "#e34c26" },
  json:       { label: "JSON",       color: "#cbcb41" },
  yaml:       { label: "YAML",       color: "#cb171e" },
  toml:       { label: "TOML",       color: "#9c4121" },
  xml:        { label: "XML",        color: "#e37933" },
  sql:        { label: "SQL",        color: "#e38c00" },
  rs:         { label: "Rust",       color: "#dea584" },
  rust:       { label: "Rust",       color: "#dea584" },
  go:         { label: "Go",         color: "#00add8" },
  java:       { label: "Java",       color: "#b07219" },
  cpp:        { label: "C++",        color: "#f34b7d" },
  c:          { label: "C",          color: "#555555" },
  rb:         { label: "Ruby",       color: "#701516" },
  kt:         { label: "Kotlin",     color: "#a97bff" },
  swift:      { label: "Swift",      color: "#f05138" },
  php:        { label: "PHP",        color: "#4f5d95" },
  md:         { label: "Markdown",   color: "#083fa1" },
  markdown:   { label: "Markdown",   color: "#083fa1" },
};
function getLangMeta(lang: string) {
  return LANG_META[lang.toLowerCase()] ?? {
    label: lang.charAt(0).toUpperCase() + lang.slice(1) || "Text",
    color: "rgba(160,160,200,0.5)",
  };
}

const GUTTER_MIN = 4; // mostra numeri riga solo se ≥ 4 righe

// ── Gutter component ──────────────────────────────────────────────────────
function Gutter({ count }: { count: number }) {
  return (
    <div aria-hidden="true" style={{
      display: "flex", flexDirection: "column", alignItems: "flex-end",
      padding: "14px 10px 14px 10px", minWidth: 34,
      userSelect: "none", flexShrink: 0,
      borderRight: "1px solid rgba(255,255,255,0.05)",
      background: "rgba(0,0,0,0.12)",
    }}>
      {Array.from({ length: count }, (_, i) => (
        <span key={i} style={{
          fontSize: "0.72rem", lineHeight: 1.65,
          color: "rgba(150,150,175,0.28)",
          fontFamily: "'JetBrains Mono',Menlo,monospace",
          fontVariantNumeric: "tabular-nums",
        }}>
          {i + 1}
        </span>
      ))}
    </div>
  );
}

const CodeBlock = memo(({ code, language = "", onExecuteResult }: CodeBlockProps) => {
  const [copied, setCopied] = useState(false);
  const [collapsed, setCollapsed] = useState(false);
  const [highlighted, setHighlighted] = useState<string | null>(null);

  const lineCount   = useMemo(() => (code.match(/\n/g) || []).length + 1, [code]);
  const isExec      = language === "execute";
  const meta        = getLangMeta(language || "text");
  const showGutter  = lineCount >= GUTTER_MIN && !isExec;

  useEffect(() => {
    if (isExec) return;
    let cancelled = false;
    const doHighlight = () => {
      _getShiki().then(highlighter => {
        if (cancelled) return;
        if (!highlighter) { setHighlighted(null); return; }
        // Risolvi alias (py → python, sh → bash, ecc.)
        const rawLang = (language || "").toLowerCase();
        const resolvedLang = _SHIKI_ALIAS[rawLang] ?? rawLang;
        const safeLang = _SHIKI_LANGS.includes(resolvedLang) ? resolvedLang : "text";
        try {
          const html = highlighter.codeToHtml(code, { lang: safeLang, theme: _SHIKI_THEME });
          if (!cancelled) setHighlighted(_extractCode(html));
        } catch {
          if (!cancelled) setHighlighted(null);
        }
      }).catch(() => { if (!cancelled) setHighlighted(null); });
    };
    // S225: Safari/iPhone — defer syntax highlight to browser idle time
    // evita di bloccare il main thread durante lo streaming di messaggi
    if (typeof requestIdleCallback !== "undefined") {
      const id = requestIdleCallback(doHighlight, { timeout: 2000 });
      return () => { cancelled = true; cancelIdleCallback(id); };
    }
    doHighlight();
    return () => { cancelled = true; };
  }, [code, language, isExec]);

  const copy = () => {
    navigator.clipboard.writeText(code).then(() => {
      haptic("copy"); // AUT-4: feedback aptico su Android PWA
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    }).catch(() => {});
  };

  if (isExec) {
    return <CodeRunner code={code} onResult={onExecuteResult} />;
  }

  return (
    <div style={{
      borderRadius: 10,
      border: "1px solid rgba(255,255,255,0.07)",
      background: "rgba(0,0,0,0.35)",
      overflow: "hidden",
      margin: "0.5em 0 0.9em",
      fontSize: "0.82rem",
    }}>
      {/* Toolbar */}
      <div
        role="button"
        tabIndex={0}
        onClick={() => setCollapsed(c => !c)}
        onKeyDown={e => e.key === "Enter" && setCollapsed(c => !c)}
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          padding: "7px 12px",
          background: "rgba(255,255,255,0.03)",
          borderBottom: collapsed ? "none" : "1px solid rgba(255,255,255,0.06)",
          cursor: "pointer",
          userSelect: "none",
          gap: 8,
        }}
      >
        {/* Left: chevron + lang dot + label + line count */}
        <div style={{ display: "flex", alignItems: "center", gap: 7, minWidth: 0 }}>
          {collapsed
            ? <ChevronRight size={13} style={{ color: "rgba(180,180,200,0.45)", flexShrink: 0 }} />
            : <ChevronDown  size={13} style={{ color: "rgba(180,180,200,0.45)", flexShrink: 0 }} />
          }
          {/* Pallino colore linguaggio */}
          <span style={{
            width: 8, height: 8, borderRadius: "50%",
            background: meta.color, flexShrink: 0,
            boxShadow: `0 0 5px ${meta.color}55`,
          }} />
          <span style={{
            fontSize: "0.72rem", fontWeight: 600,
            color: "rgba(220,220,240,0.75)",
            fontFamily: "monospace", letterSpacing: "0.02em",
          }}>
            {meta.label}
          </span>
          <span style={{
            fontSize: "0.63rem",
            color: "rgba(140,140,170,0.4)",
            fontFamily: "monospace",
          }}>
            {lineCount} {lineCount === 1 ? "riga" : "righe"}
          </span>
        </div>

        {/* Right: copy button */}
        <button
          onClick={e => { e.stopPropagation(); copy(); }}
          title={copied ? "Copiato!" : "Copia codice"}
          style={{
            all: "unset",
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            gap: 5,
            padding: "3px 8px",
            borderRadius: 6,
            fontSize: "0.68rem",
            fontWeight: 500,
            color: copied ? "#7c7cff" : "rgba(160,160,200,0.55)",
            background: copied ? "rgba(124,124,255,0.08)" : "transparent",
            border: copied ? "1px solid rgba(124,124,255,0.18)" : "1px solid transparent",
            transition: "all 0.2s",
            flexShrink: 0,
          }}
          onMouseEnter={e => {
            if (!copied) {
              e.currentTarget.style.color = "rgba(200,200,230,0.85)";
              e.currentTarget.style.background = "rgba(255,255,255,0.05)";
            }
          }}
          onMouseLeave={e => {
            if (!copied) {
              e.currentTarget.style.color = "rgba(160,160,200,0.55)";
              e.currentTarget.style.background = "transparent";
            }
          }}
        >
          {copied
            ? <><Check size={11} /><span>Copiato</span></>
            : <><Copy size={11} /><span>Copia</span></>
          }
        </button>
      </div>

      {/* Code body + gutter */}
      {!collapsed && (
        <div style={{ display: "flex", overflowX: "auto" }}>
          {showGutter && <Gutter count={lineCount} />}
          <div style={{ flex: 1, padding: "14px 16px" }}>
            {highlighted !== null ? (
              <pre style={{
                margin: 0, padding: 0,
                fontFamily: "'JetBrains Mono','Fira Code','Cascadia Code',Menlo,Monaco,Consolas,monospace",
                fontSize: "0.82rem", lineHeight: 1.65,
                color: "#d4d4d8", whiteSpace: "pre",
              }}>
                <code
                  className={`language-${language || "text"}`}
                  dangerouslySetInnerHTML={{ __html: highlighted }}
                />
              </pre>
            ) : (
              <pre style={{
                margin: 0, padding: 0,
                fontFamily: "'JetBrains Mono','Fira Code',Menlo,Monaco,Consolas,monospace",
                fontSize: "0.82rem", lineHeight: 1.65,
                color: "#d4d4d8", whiteSpace: "pre",
              }}>
                <code>{code}</code>
              </pre>
            )}
          </div>
        </div>
      )}
    </div>
  );
});

CodeBlock.displayName = "CodeBlock";
export default CodeBlock;
