import React, { useState, useEffect } from "react";
import { ChevronRight, ChevronDown, Terminal, FileText, FolderTree, Wrench, AlertCircle, Globe, Search, Pencil, Trash2, Move, FileSearch, Compass, Sparkles, History, MousePointer2, Eye, EyeOff, Copy, Check, ImageIcon, CheckSquare } from "lucide-react";
import { toast } from "sonner";
import { hasImagePayload, hasToolPreview } from "../lib/resolveToolPreview";
import { mergeImageFields } from "../lib/imagePreview";
import GeneratedImagePreview from "./GeneratedImagePreview";
import { getFileContentFromToolEvent, isCopyableFileToolEvent } from "../lib/filePreview";
import ChatPreviewBubble from "./ChatPreviewBubble";
import ImageGeneratingPlaceholder from "./ImageGeneratingPlaceholder";

const ICONS = {
  exec_shell: Terminal,
  read_file: FileText,
  write_file: FileText,
  edit_file: Pencil,
  list_dir: FolderTree,
  grep: Search,
  find_files: FileSearch,
  delete_path: Trash2,
  move_path: Move,
  web_search: Search,
  web_fetch: Globe,
  browser_visit: Compass,
  browser_open: Compass,
  browser_click: MousePointer2,
  browser_type: Compass,
  browser_fill: Compass,
  browser_snapshot: Compass,
  browser_scroll: Compass,
  browser_press: Compass,
  browser_close: Compass,
  emo_reflect: Sparkles,
  emo_think: Sparkles,
  emo_todo: CheckSquare,
  emo_remember: Sparkles,
  emo_introspect: Sparkles,
  emo_read_self: Sparkles,
  emo_edit_self: Sparkles,
  emo_list_self_saves: History,
  emo_restore_self: History,
  generate_image: ImageIcon,
};

const COLORS = {
  exec_shell: "#06B6D4",
  read_file: "#A855F7",
  write_file: "#EC4899",
  edit_file: "#F472B6",
  list_dir: "#F59E0B",
  grep: "#22D3EE",
  find_files: "#818CF8",
  delete_path: "#EF4444",
  move_path: "#FB923C",
  web_search: "#10B981",
  web_fetch: "#3B82F6",
  browser_visit: "#6366F1",
  browser_open: "#6366F1",
  browser_click: "#38BDF8",
  browser_type: "#818CF8",
  browser_fill: "#818CF8",
  emo_reflect: "#E879F9",
  emo_think: "#E879F9",
  emo_todo: "#34D399",
  emo_remember: "#C084FC",
  emo_introspect: "#A855F7",
  emo_read_self: "#E879F9",
  emo_edit_self: "#E879F9",
  emo_list_self_saves: "#C084FC",
  emo_restore_self: "#C084FC",
  generate_image: "#E879F9",
};

export const ToolCallCard = ({ event, liveHtmlByPath = {}, showCopyCode = false }) => {
  const [open, setOpen] = useState(event.state !== "done");
  const [copied, setCopied] = useState(false);
  const isImageGen = event.tool === "generate_image";
  const imageFields = mergeImageFields(event.inlinePreview, event.result);
  const hasImageData = isImageGen && hasImagePayload(imageFields);
  const canPreview = hasToolPreview(event) || hasImageData || Boolean(
    event.args?.url && [
      "browser_visit", "browser_open", "web_fetch",
      "browser_click", "browser_snapshot", "browser_scroll", "browser_press", "browser_type", "browser_fill",
    ].includes(event.tool),
  );
  const [previewOpen, setPreviewOpen] = useState(
    canPreview && (event.state === "done" || ["browser_visit", "browser_open"].includes(event.tool)),
  );
  const Icon = ICONS[event.tool] || Wrench;
  const color = COLORS[event.tool] || "var(--mode-color)";
  const isError = event.state === "error" || (event.result && event.result.ok === false);
  const isExecuting = event.state === "executing";
  const showImageGenLoading = isImageGen && isExecuting;
  const fileContent = showCopyCode && isCopyableFileToolEvent(event)
    ? getFileContentFromToolEvent(event, liveHtmlByPath)
    : "";
  const canCopyCode = Boolean(fileContent);

  const handleCopyCode = async () => {
    if (!fileContent) return;
    try {
      await navigator.clipboard.writeText(fileContent);
      setCopied(true);
      toast.success("Code copié");
      setTimeout(() => setCopied(false), 2000);
    } catch {
      toast.error("Impossible de copier");
    }
  };

  useEffect(() => {
    if (isImageGen && isExecuting) {
      setPreviewOpen(true);
    } else if (event.state === "done" && canPreview) {
      setPreviewOpen(true);
    }
  }, [event.state, canPreview, event.inlinePreview, event.result, isImageGen, isExecuting]);

  const summary = (() => {
    if (isExecuting) return "En cours…";
    if (isError) return event.result?.error || "erreur";
    if (event.result?.exit_code !== undefined) return `code ${event.result.exit_code}`;
    if (event.result?.count !== undefined) return `${event.result.count} résultats`;
    if (event.result?.results !== undefined) return `${event.result.results.length} résultats`;
    if (event.result?.text !== undefined && event.result?.url !== undefined) return `${event.result.text.length} car.`;
    if (event.result?.content !== undefined) return `${event.result.content.length} car.`;
    if (event.result?.matches !== undefined) return `${event.result.matches.length} correspondances`;
    if (event.result?.entries !== undefined) return `${event.result.entries.length} entrées`;
    if (event.result?.replacements !== undefined) return `${event.result.replacements} remplacement(s)`;
    if (event.result?.files !== undefined && event.result?.dirs !== undefined) return `${event.result.files.length} fichiers · ${event.result.dirs.length} dossiers`;
    if (event.result?.files !== undefined && Array.isArray(event.result.files)) return `${event.result.files.length} fichiers`;
    return "ok";
  })();

  return (
    <div className="space-y-2 my-2">
      <div
        data-testid={`tool-call-${event.tool}`}
        className="rounded-xl overflow-hidden"
        style={{
          background: "var(--emo-card-bg)",
          border: `1px solid ${isError ? "rgba(239,68,68,0.3)" : "var(--emo-border)"}`,
        }}
      >
        <div className="flex items-center gap-1">
          <button
            onClick={() => setOpen(!open)}
            className="flex-1 flex items-center gap-2.5 px-3 py-2 text-xs em-hover-subtle transition min-w-0"
          >
            {open ? <ChevronDown size={12} className="opacity-50 flex-shrink-0" /> : <ChevronRight size={12} className="opacity-50 flex-shrink-0" />}
            <Icon size={13} style={{ color }} className="flex-shrink-0" />
            <span className="font-code text-[12px] flex-shrink-0" style={{ color }}>{event.tool}</span>
            <span className="text-secondary-em font-code truncate flex-1 text-left">
              {formatArgs(event.tool, event.args)}
            </span>
            {isExecuting ? (
              <span className="inline-flex items-center gap-1 text-[10px] text-secondary-em flex-shrink-0">
                <span className="w-1.5 h-1.5 rounded-full animate-pulse" style={{ background: color }} />
                En cours
              </span>
            ) : (
          <span
            className="text-[10px] px-2 py-0.5 rounded-full flex-shrink-0"
            style={{
              background: isError ? "var(--emo-error-bg)" : "var(--emo-success-bg)",
              color: isError ? "var(--emo-error-text)" : "var(--emo-success-text)",
            }}
          >
                {isError && <AlertCircle size={9} className="inline mr-1" />}
                {summary}
              </span>
            )}
          </button>
          {canCopyCode && event.state === "done" && !isError && (
            <button
              type="button"
              data-testid="tool-copy-code-btn"
              onClick={handleCopyCode}
              className="flex-shrink-0 flex items-center gap-1 px-2.5 py-2 text-[10px] em-hover transition border-l em-border-l"
              style={{ color: copied ? "var(--emo-success-text)" : "var(--emo-text-muted)" }}
              title="Copier tout le code"
            >
              {copied ? <Check size={12} /> : <Copy size={12} />}
              <span className="hidden sm:inline">{copied ? "Copié" : "Copier"}</span>
            </button>
          )}
          {canPreview && event.state === "done" && !isError && (
            <button
              type="button"
              data-testid="tool-preview-toggle"
              onClick={() => setPreviewOpen((v) => !v)}
              className="flex-shrink-0 flex items-center gap-1 px-2.5 py-2 text-[10px] em-hover transition border-l em-border-l"
              style={{ color: previewOpen ? "var(--mode-color)" : "var(--emo-text-muted)" }}
              title={previewOpen ? "Masquer l'aperçu" : "Afficher l'aperçu"}
            >
              {previewOpen ? <EyeOff size={12} /> : <Eye size={12} />}
              <span className="hidden sm:inline">{previewOpen ? "Masquer" : "Aperçu"}</span>
            </button>
          )}
        </div>
        {open && (
          <div className="px-3 pb-3 pt-1 em-border-t space-y-2">
            {event.args && Object.keys(event.args).length > 0 && (
              <div>
                <div className="text-[9px] uppercase tracking-[0.18em] text-muted-em mb-1">Arguments</div>
                <pre className="font-code text-[11px] p-2 rounded overflow-x-auto" style={{ background: "var(--emo-pre-bg)", color: "var(--emo-code-text)" }}>
                  {JSON.stringify(event.args, null, 2)}
                </pre>
              </div>
            )}
            {event.result && (
              <div>
                <div className="text-[9px] uppercase tracking-[0.18em] text-muted-em mb-1">Résultat</div>
                <pre className="font-code text-[11px] p-2 rounded overflow-x-auto max-h-64 overflow-y-auto" style={{ background: "var(--emo-pre-bg)", color: isError ? "var(--emo-error-text)" : "var(--emo-code-text)" }}>
                  {formatResult(event.result)}
                </pre>
              </div>
            )}
          </div>
        )}
      </div>

      {previewOpen && showImageGenLoading && (
        <ImageGeneratingPlaceholder prompt={event.args?.prompt} />
      )}

      {previewOpen && isImageGen && event.state === "done" && !isError && !showImageGenLoading && (
        <GeneratedImagePreview
          sources={[event.inlinePreview, event.result]}
          title={event.args?.prompt || event.result?.prompt || event.result?.subject || "Image générée"}
          className="mt-2"
          testId="tool-image-preview"
        />
      )}

      {previewOpen && !isImageGen && canPreview && !showImageGenLoading && (
        <ChatPreviewBubble
          event={event}
          liveHtmlByPath={liveHtmlByPath}
          showCopyCode={showCopyCode}
        />
      )}
    </div>
  );
};

function formatArgs(tool, args) {
  if (!args) return "";
  if (tool === "exec_shell") return args.cmd || "";
  if (tool === "read_file" || tool === "list_dir" || tool === "delete_path") return args.path || "";
  if (tool === "write_file") return `${args.path} (${(args.content || "").length} car.)`;
  if (tool === "edit_file") return args.path || "";
  if (tool === "grep") return `"${args.pattern || ""}" in ${args.path || "."}`;
  if (tool === "find_files") return args.pattern || "";
  if (tool === "move_path") return `${args.from} → ${args.to}`;
  if (tool === "web_search") return `"${args.query || ""}"${args.focus && args.focus !== "general" ? ` [${args.focus}]` : ""}`;
  if (tool === "web_fetch" || tool === "browser_visit" || tool === "browser_open") return args.url || "";
  if (tool.startsWith("browser_")) {
    if (args.x != null && args.y != null) return `@${args.x},${args.y}`;
    if (args.ref != null) return `ref=${args.ref}`;
    if (args.selector) return args.selector;
    if (args.text) return `"${String(args.text).slice(0, 40)}"`;
    return args.url || "";
  }
  if (tool === "emo_reflect" || tool === "emo_think") return (args.thought || "").slice(0, 60);
  if (tool === "emo_todo") return (args.action || "todo") + (args.text ? `: ${args.text}` : "");
  if (tool === "emo_remember") return (args.content || "").slice(0, 60);
  if (tool === "emo_edit_self") return `${args.section || ""} (${(args.content || "").length} car.)`;
  if (tool === "emo_read_self") return args.section || "tout";
  if (tool === "emo_restore_self") return (args.version_id || "").slice(0, 8);
  if (tool === "generate_image") return (args.prompt || "").slice(0, 80);
  return JSON.stringify(args);
}

function formatResult(result) {
  if (!result) return "";
  if (result.ok === false) return `ERREUR : ${result.error}`;
  if (result.stdout !== undefined || result.stderr !== undefined) {
    let out = "";
    if (result.stdout) out += result.stdout;
    if (result.stderr) out += (out ? "\n--- stderr ---\n" : "") + result.stderr;
    return out || "(aucune sortie)";
  }
  if (result.results !== undefined) {
    return result.results.map((r, i) => {
      const dom = r.domain ? ` (${r.domain})` : "";
      return `${i + 1}. ${r.title}${dom}\n   ${r.url}\n   ${r.snippet || ""}`;
    }).join("\n\n").slice(0, 4000);
  }
  if (result.text !== undefined && result.url !== undefined) {
    let s = `📄 ${result.title || "(sans titre)"}\n🔗 ${result.url}\n\n`;
    s += result.text.slice(0, 3000);
    if (result.truncated) s += "\n\n... [tronqué]";
    if (result.links?.length) {
      s += `\n\n--- ${result.links.length} liens ---\n`;
      s += result.links.slice(0, 10).map((l) => `· ${l.text} → ${l.url}`).join("\n");
    }
    return s;
  }
  if (result.content !== undefined) return result.content.slice(0, 4000);
  if (result.matches !== undefined) {
    return result.matches.map((m) => `${m.file}:${m.line}: ${m.text}`).join("\n").slice(0, 4000);
  }
  if (result.entries !== undefined) {
    return result.entries.map((e) => `${e.is_dir ? "[dir]" : "     "} ${e.path}`).join("\n").slice(0, 4000);
  }
  if (result.files !== undefined && result.dirs !== undefined) {
    return `📁 ${result.path}\n\n` +
      result.dirs.map((d) => `[dir]  ${d}`).join("\n") + "\n" +
      result.files.map((f) => `       ${f}`).join("\n");
  }
  if (result.files !== undefined && Array.isArray(result.files)) {
    return result.files.join("\n").slice(0, 4000);
  }
  return JSON.stringify(result, null, 2);
}

export default ToolCallCard;
