"use client";

import { useState, useRef, useEffect, useCallback } from "react";
import { Send, Square, User, Bot, Wrench, Plus, Hammer, ImageIcon, Check, X, ZoomIn, ZoomOut, RotateCcw, FilePlus, History, Brain, FolderOpen, Copy, CheckCheck } from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";

import { cn } from "@/lib/utils";
import { API_BASE_URL } from "@/lib/config";
import { validateFile, fileToBase64, fileToText, isImageFile, formatFileSize, type AttachedFile } from "@/lib/file-utils";
import { FilePreviewChips } from "@/components/chat/FilePreviewChips";
import { MCPToolsPanel } from "@/components/chat/MCPToolsPanel";
import { SessionPanel } from "@/components/chat/SessionPanel";
import { MemoryPanel } from "@/components/chat/MemoryPanel";
import { ThinkingBlock, type ThinkingStep } from "@/components/chat/ThinkingBlock";
import { loadProfile, loadProfileFromServer, type UserProfile } from "@/lib/stores/profile";
import { loadTheme, saveTheme, type ThemeSettings } from "@/lib/stores/theme";
import { loadSession, saveSession, clearSession } from "@/lib/stores/session";
import { createSession, fetchSession, saveMessages as saveMessagesApi, type SessionMessage } from "@/lib/api/sessions";
import { fetchWorkspaces, type WorkspaceInfo } from "@/lib/api/workspace";

type MessageContent =
  | string
  | Array<{ type: "text"; text: string } | { type: "image_url"; image_url: { url: string } }>;

type AttachedFileMeta = { name: string; size: number; isImage: boolean };

type Message = {
  role: "user" | "assistant" | "tool";
  content: MessageContent;
  name?: string;
  tool_call_id?: string;
  _images?: string[];
  _thinkingSteps?: ThinkingStep[];
  _files?: AttachedFileMeta[];
  _displayText?: string; // user-facing text (without file content)
};

function getTextContent(content: MessageContent): string {
  if (!content) return "";
  if (typeof content === "string") return content;
  if (!Array.isArray(content)) return "";
  const textPart = content.find((p) => p.type === "text");
  return textPart ? (textPart as { type: "text"; text: string }).text : "";
}

function getImageUrls(content: MessageContent): string[] {
  if (!content || typeof content === "string") return [];
  if (!Array.isArray(content)) return [];
  return content
    .filter((p) => p.type === "image_url")
    .map((p) => (p as { type: "image_url"; image_url: { url: string } }).image_url.url);
}

function makeWelcomeMessage(botName: string): Message {
  return { role: "assistant", content: `안녕하세요! ${botName || "AI 어시스턴트"}입니다. 무엇을 도와드릴까요?` };
}

const WELCOME_MESSAGE: Message = { role: "assistant", content: "안녕하세요! 무엇을 도와드릴까요?" };

function CopyButton({ text }: { text: string }) {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      /* fallback: ignore */
    }
  };
  return (
    <button
      onClick={handleCopy}
      className="inline-flex items-center gap-1 text-[9px] font-bold text-muted-foreground/30 hover:text-muted-foreground/60 transition-colors uppercase tracking-[0.2em]"
      title="복사"
    >
      {copied ? <CheckCheck size={11} className="text-primary/60" /> : <Copy size={11} />}
      {copied && <span className="text-primary/60">복사됨</span>}
    </button>
  );
}

export function ChatInterface() {
  const [messages, setMessages] = useState<Message[]>([WELCOME_MESSAGE]);
  const [input, setInput] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [attachedFiles, setAttachedFiles] = useState<AttachedFile[]>([]);
  const [thinkingSteps, setThinkingSteps] = useState<ThinkingStep[]>([]);
  const [mcpPanelOpen, setMcpPanelOpen] = useState(false);
  const [sessionPanelOpen, setSessionPanelOpen] = useState(false);
  const [memoryPanelOpen, setMemoryPanelOpen] = useState(false);
  const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);
  const [profile, setProfile] = useState<UserProfile>({ name: "", avatar: "", platformName: "Track Platform", platformSubtitle: "Nexus System", botName: "Nexus Platform Core", botAvatar: "" });
  const [activeWorkspace, setActiveWorkspace] = useState<WorkspaceInfo | null>(null);
  const sessionInitRef = useRef(false);
  const sessionIdRef = useRef<string | null>(null);

  // Background settings
  const [chatBgImage, setChatBgImage] = useState("/rubber-track.png");
  const [chatBgOpacity, setChatBgOpacity] = useState(0.3);
  const [chatBgScale, setChatBgScale] = useState(1.1);
  const [chatBgPosX, setChatBgPosX] = useState(50);
  const [chatBgPosY, setChatBgPosY] = useState(50);

  // Edit mode for background positioning
  const [bgEditMode, setBgEditMode] = useState(false);
  const [editScale, setEditScale] = useState(1.1);
  const [editPosX, setEditPosX] = useState(50);
  const [editPosY, setEditPosY] = useState(50);
  const [editOpacity, setEditOpacity] = useState(0.3);
  const [dragging, setDragging] = useState(false);
  const dragStartRef = useRef({ x: 0, y: 0, posX: 50, posY: 50 });
  const bgContainerRef = useRef<HTMLDivElement>(null);

  const scrollRef = useRef<HTMLDivElement>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const [fileDragOver, setFileDragOver] = useState(false);
  const dragCounterRef = useRef(0);
  const abortControllerRef = useRef<AbortController | null>(null);
  const syncingRef = useRef(false);

  const loadBgFromTheme = useCallback(() => {
    const t = loadTheme();
    setChatBgImage(t.chatBgImage);
    setChatBgOpacity(t.chatBgOpacity);
    setChatBgScale(t.chatBgScale);
    setChatBgPosX(t.chatBgPositionX);
    setChatBgPosY(t.chatBgPositionY);
  }, []);

  useEffect(() => {
    const p = loadProfile();
    setProfile(p);
    loadProfileFromServer().then(setProfile).catch(() => {});
    loadBgFromTheme();

    // Restore session from localStorage on mount
    if (!sessionInitRef.current) {
      sessionInitRef.current = true;
      const stored = loadSession();
      if (stored.messages.length > 0) {
        setMessages(stored.messages as Message[]);
        setCurrentSessionId(stored.sessionId);
        sessionIdRef.current = stored.sessionId;
      } else {
        setMessages([makeWelcomeMessage(p.botName)]);
      }
    }

    // Load active workspace
    fetchWorkspaces()
      .then((list) => setActiveWorkspace(list.find((w) => w.is_active) ?? null))
      .catch(() => {});

    const profileHandler = () => setProfile(loadProfile());
    const themeHandler = () => loadBgFromTheme();
    window.addEventListener("profile-change", profileHandler);
    window.addEventListener("theme-change", themeHandler);
    return () => {
      window.removeEventListener("profile-change", profileHandler);
      window.removeEventListener("theme-change", themeHandler);
    };
  }, [loadBgFromTheme]);

  // Keep ref in sync with state
  useEffect(() => {
    sessionIdRef.current = currentSessionId;
  }, [currentSessionId]);

  // Auto-save to localStorage on message changes
  useEffect(() => {
    if (!sessionInitRef.current) return;
    saveSession({ sessionId: currentSessionId, messages });
  }, [messages, currentSessionId]);

  useEffect(() => {
    requestAnimationFrame(() => {
      if (scrollRef.current) {
        scrollRef.current.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
      }
    });
  }, [messages, thinkingSteps]);

  // --- BG Edit handlers ---
  const enterBgEdit = () => {
    setEditScale(chatBgScale);
    setEditPosX(chatBgPosX);
    setEditPosY(chatBgPosY);
    setEditOpacity(chatBgOpacity);
    setBgEditMode(true);
  };

  const saveBgEdit = () => {
    const theme = loadTheme();
    const next: ThemeSettings = {
      ...theme,
      chatBgScale: editScale,
      chatBgPositionX: editPosX,
      chatBgPositionY: editPosY,
      chatBgOpacity: editOpacity,
    };
    saveTheme(next);
    setChatBgScale(editScale);
    setChatBgPosX(editPosX);
    setChatBgPosY(editPosY);
    setChatBgOpacity(editOpacity);
    setBgEditMode(false);
    window.dispatchEvent(new Event("theme-change"));
  };

  const cancelBgEdit = () => {
    setBgEditMode(false);
  };

  const resetBgEdit = () => {
    setEditScale(1.1);
    setEditPosX(50);
    setEditPosY(50);
    setEditOpacity(0.3);
  };

  const handleDragStart = (e: React.MouseEvent) => {
    e.preventDefault();
    setDragging(true);
    dragStartRef.current = { x: e.clientX, y: e.clientY, posX: editPosX, posY: editPosY };
  };

  useEffect(() => {
    if (!dragging) return;
    const handleMove = (e: MouseEvent) => {
      const container = bgContainerRef.current;
      if (!container) return;
      const rect = container.getBoundingClientRect();
      const dx = e.clientX - dragStartRef.current.x;
      const dy = e.clientY - dragStartRef.current.y;
      // Convert pixel delta to percentage (inverted: drag right = position moves left)
      const pctX = (dx / rect.width) * 100;
      const pctY = (dy / rect.height) * 100;
      setEditPosX(Math.max(0, Math.min(100, dragStartRef.current.posX - pctX)));
      setEditPosY(Math.max(0, Math.min(100, dragStartRef.current.posY - pctY)));
    };
    const handleUp = () => setDragging(false);
    window.addEventListener("mousemove", handleMove);
    window.addEventListener("mouseup", handleUp);
    return () => {
      window.removeEventListener("mousemove", handleMove);
      window.removeEventListener("mouseup", handleUp);
    };
  }, [dragging]);

  // Wheel zoom in edit mode
  const handleWheel = useCallback((e: WheelEvent) => {
    e.preventDefault();
    setEditScale((prev) => Math.max(0.5, Math.min(5, prev + (e.deltaY > 0 ? -0.1 : 0.1))));
  }, []);

  useEffect(() => {
    if (!bgEditMode) return;
    const container = bgContainerRef.current;
    if (!container) return;
    container.addEventListener("wheel", handleWheel, { passive: false });
    return () => container.removeEventListener("wheel", handleWheel);
  }, [bgEditMode, handleWheel]);

  // --- File / send handlers ---
  const processFiles = useCallback(async (fileList: File[]) => {
    for (const file of fileList) {
      const error = validateFile(file);
      if (error) {
        alert(error);
        continue;
      }
      const image = isImageFile(file);
      const base64 = await fileToBase64(file);
      const attached: AttachedFile = {
        id: crypto.randomUUID?.() ?? Math.random().toString(36).slice(2) + Date.now().toString(36),
        file,
        preview: image ? URL.createObjectURL(file) : "",
        base64,
        mimeType: file.type,
        isImage: image,
      };
      setAttachedFiles((prev) => [...prev, attached]);
    }
  }, []);

  const handleFileSelect = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files) return;
    await processFiles(Array.from(files));
    e.target.value = "";
  }, [processFiles]);

  const removeFile = useCallback((id: string) => {
    setAttachedFiles((prev) => {
      const file = prev.find((f) => f.id === id);
      if (file && file.preview) URL.revokeObjectURL(file.preview);
      return prev.filter((f) => f.id !== id);
    });
  }, []);

  // Drag & drop handlers
  const handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current++;
    if (e.dataTransfer.types.includes("Files")) setFileDragOver(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current--;
    if (dragCounterRef.current === 0) setFileDragOver(false);
  }, []);

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
  }, []);

  const handleDrop = useCallback(async (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragCounterRef.current = 0;
    setFileDragOver(false);
    const files = Array.from(e.dataTransfer.files);
    if (files.length > 0) await processFiles(files);
  }, [processFiles]);

  const handlePaste = useCallback(async (e: React.ClipboardEvent) => {
    const items = Array.from(e.clipboardData.items);
    const imageFiles = items
      .filter((item) => item.type.startsWith("image/"))
      .map((item) => item.getAsFile())
      .filter((f): f is File => f !== null);
    if (imageFiles.length === 0) return;
    e.preventDefault();
    await processFiles(imageFiles);
  }, [processFiles]);

  const handleStop = useCallback(() => {
    abortControllerRef.current?.abort();
  }, []);

  const handleSend = async () => {
    if ((!input.trim() && attachedFiles.length === 0) || isLoading) return;

    let userContent: MessageContent;
    let displayImages: string[] = [];

    let fileMetas: AttachedFileMeta[] | undefined;

    if (attachedFiles.length > 0) {
      const parts: Array<{ type: "text"; text: string } | { type: "image_url"; image_url: { url: string } }> = [];
      const fileDescriptions: string[] = [];
      fileMetas = [];

      for (const f of attachedFiles) {
        fileMetas.push({ name: f.file.name, size: f.file.size, isImage: f.isImage });
        if (f.isImage) {
          parts.push({ type: "image_url", image_url: { url: f.base64 } });
          displayImages.push(f.base64);
        } else {
          try {
            const text = await fileToText(f.file);
            fileDescriptions.push(`[첨부파일: ${f.file.name} (${formatFileSize(f.file.size)})]\n\`\`\`\n${text.slice(0, 50000)}\n\`\`\``);
          } catch {
            fileDescriptions.push(`[첨부파일: ${f.file.name} (${f.mimeType}, ${formatFileSize(f.file.size)}) — 바이너리 파일]`);
          }
        }
      }

      const textParts: string[] = [];
      if (fileDescriptions.length > 0) textParts.push(fileDescriptions.join("\n\n"));
      if (input.trim()) textParts.push(input);

      if (textParts.length > 0) {
        parts.push({ type: "text", text: textParts.join("\n\n") });
      }
      userContent = parts.length > 0 ? parts : (textParts.join("\n\n") || input);
    } else {
      userContent = input;
    }

    const userMessage: Message = {
      role: "user",
      content: userContent,
      _images: displayImages.length > 0 ? displayImages : undefined,
      _files: fileMetas,
      _displayText: input.trim() || undefined,
    };

    setMessages((prev) => [...prev, userMessage]);
    setInput("");
    if (textareaRef.current) textareaRef.current.style.height = "auto";
    attachedFiles.forEach((f) => URL.revokeObjectURL(f.preview));
    setAttachedFiles([]);
    setIsLoading(true);
    setThinkingSteps([]);

    const abortController = new AbortController();
    abortControllerRef.current = abortController;
    let finalContent = "";
    const collectedSteps: ThinkingStep[] = [];

    try {
      const apiMessages = [...messages, userMessage].map((m) => ({
        role: m.role,
        content: m.content,
      }));

      const response = await fetch(`${API_BASE_URL}/api/chat/stream`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ messages: apiMessages }),
        signal: abortController.signal,
      });

      if (!response.ok) throw new Error("API request failed");

      const reader = response.body!.getReader();
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split("\n\n");
        buffer = lines.pop()!;

        for (const line of lines) {
          if (!line.startsWith("data: ")) continue;
          let event: Record<string, unknown>;
          try {
            event = JSON.parse(line.slice(6));
          } catch {
            continue;
          }

          switch (event.type) {
            case "thinking":
              collectedSteps.push({ type: "thinking", content: event.content as string });
              setThinkingSteps([...collectedSteps]);
              break;
            case "tool_call":
              collectedSteps.push({ type: "tool_call", name: event.name as string });
              setThinkingSteps([...collectedSteps]);
              break;
            case "tool_result": {
              const step: ThinkingStep = { type: "tool_result", name: event.name as string, result: event.result as string };
              if ("success" in event) step.success = event.success as boolean;
              collectedSteps.push(step);
              setThinkingSteps([...collectedSteps]);
              break;
            }
            case "error":
              collectedSteps.push({ type: "error", content: event.content as string });
              setThinkingSteps([...collectedSteps]);
              break;
            case "content":
              finalContent = event.content as string;
              break;
          }
        }
      }

      const newAssistantMsg: Message = {
        role: "assistant",
        content: finalContent || "응답을 생성하지 못했습니다.",
        _thinkingSteps: collectedSteps.length > 0 ? collectedSteps : undefined,
      };

      const allMessages = [...messages, userMessage, newAssistantMsg];
      setMessages(allMessages);
      syncToBackend(allMessages);
    } catch (error) {
      if (error instanceof DOMException && error.name === "AbortError") {
        const partialMsg: Message = {
          role: "assistant",
          content: finalContent || "(응답이 중단되었습니다.)",
          _thinkingSteps: collectedSteps.length > 0 ? collectedSteps : undefined,
        };
        setMessages((prev) => [...prev, partialMsg]);
      } else {
        console.error("Chat error:", error);
        setMessages((prev) => [...prev, { role: "assistant", content: "죄송합니다. 오류가 발생했습니다." }]);
      }
    } finally {
      abortControllerRef.current = null;
      setIsLoading(false);
      setThinkingSteps([]);
    }
  };

  // Convert internal Message[] to SessionMessage[] for backend
  const toSessionMessages = useCallback((msgs: Message[]): SessionMessage[] => {
    return msgs.map((m) => {
      const sm: SessionMessage = { role: m.role, content: m.content ?? "" };
      if (m._thinkingSteps?.length) sm.thinking_steps = m._thinkingSteps;
      if (m._displayText !== undefined) sm.display_text = m._displayText;
      if (m._files?.length) sm.attached_files = m._files;
      return sm;
    });
  }, []);

  // Backend sync helper — uses ref to always read the latest session ID
  const syncToBackend = useCallback(async (msgs: Message[]) => {
    if (syncingRef.current) return; // prevent concurrent calls
    syncingRef.current = true;
    try {
      let sid = sessionIdRef.current;
      if (!sid) {
        const session = await createSession();
        sid = session.id;
        setCurrentSessionId(sid);
        sessionIdRef.current = sid;
      }
      const apiMsgs = toSessionMessages(msgs);
      try {
        await saveMessagesApi(sid, apiMsgs);
      } catch {
        // Session may have been deleted — recreate and retry once
        const session = await createSession();
        sid = session.id;
        setCurrentSessionId(sid);
        sessionIdRef.current = sid;
        await saveMessagesApi(sid, apiMsgs);
      }
    } catch (e) {
      console.error("Session sync failed:", e);
    } finally {
      syncingRef.current = false;
    }
  }, [toSessionMessages]);

  // New session handler
  const handleNewSession = useCallback(async () => {
    // Save current session to backend if it has real messages
    const hasContent = messages.length > 1 || (messages.length === 1 && messages[0].role !== "assistant");
    if (hasContent && currentSessionId) {
      try {
        await saveMessagesApi(currentSessionId, toSessionMessages(messages));
      } catch (e) {
        console.error("Failed to save current session:", e);
      }
    }

    // Reset state
    setMessages([makeWelcomeMessage(profile.botName)]);
    setCurrentSessionId(null);
    sessionIdRef.current = null;
    clearSession();
  }, [messages, currentSessionId, profile.botName]);

  // Load session from archive
  const handleSelectSession = useCallback(async (sessionId: string) => {
    // Save current session first
    if (currentSessionId && messages.length > 1) {
      try {
        await saveMessagesApi(currentSessionId, toSessionMessages(messages));
      } catch (e) {
        console.error("Failed to save current session:", e);
      }
    }

    // Load selected session
    try {
      const detail = await fetchSession(sessionId);
      const loaded: Message[] = detail.messages.map((m) => ({
        role: m.role as Message["role"],
        content: m.content as MessageContent,
        name: m.name,
        tool_call_id: m.tool_call_id,
        _thinkingSteps: m.thinking_steps,
        _displayText: m.display_text,
        _files: m.attached_files,
      }));
      setMessages(loaded.length > 0 ? loaded : [makeWelcomeMessage(profile.botName)]);
      setCurrentSessionId(sessionId);
      sessionIdRef.current = sessionId;
    } catch (e) {
      console.error("Failed to load session:", e);
    }
  }, [currentSessionId, messages]);

  // Current BG values (edit mode uses draft, normal uses saved)
  const bgScale = bgEditMode ? editScale : chatBgScale;
  const bgPosX = bgEditMode ? editPosX : chatBgPosX;
  const bgPosY = bgEditMode ? editPosY : chatBgPosY;
  const bgOpacity = bgEditMode ? editOpacity : chatBgOpacity;

  return (
    <div className="flex flex-col h-full bg-background relative overflow-hidden text-foreground" ref={bgContainerRef} onDragEnter={handleDragEnter} onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={handleDrop}>
      {/* Drop overlay */}
      {fileDragOver && (
        <div className="absolute inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm border-2 border-dashed border-primary/40 rounded-xl pointer-events-none">
          <div className="flex flex-col items-center gap-3">
            <div className="w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center">
              <FilePlus className="w-8 h-8 text-primary" />
            </div>
            <span className="text-sm font-bold text-primary uppercase tracking-wider">파일을 여기에 놓으세요</span>
          </div>
        </div>
      )}
      {/* Background */}
      <div className="absolute inset-0 pointer-events-none overflow-hidden">
          <div className="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] bg-primary/5 blur-[120px] rounded-full" />
          <div className="absolute bottom-[-10%] right-[-10%] w-[40%] h-[40%] bg-primary/5 blur-[120px] rounded-full" />
          {chatBgImage && (
            <div
              className={cn("absolute inset-0 grayscale contrast-125", bgEditMode && "pointer-events-auto cursor-grab", bgEditMode && dragging && "cursor-grabbing")}
              style={{
                backgroundImage: `url("${chatBgImage}")`,
                backgroundPosition: `${bgPosX}% ${bgPosY}%`,
                backgroundSize: `${bgScale * 100}%`,
                backgroundRepeat: 'no-repeat',
                filter: 'blur(3px) grayscale(100%)',
                opacity: bgOpacity,
              }}
              onMouseDown={bgEditMode ? handleDragStart : undefined}
            />
          )}
      </div>

      {/* BG Edit overlay */}
      {bgEditMode && (
        <div className="absolute inset-0 z-40 pointer-events-none">
          {/* Grid overlay */}
          <div className="absolute inset-0 border border-primary/20" style={{
            backgroundImage: 'linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px)',
            backgroundSize: '10% 10%',
          }} />
          {/* Crosshair */}
          <div className="absolute top-1/2 left-0 right-0 h-px bg-primary/20" />
          <div className="absolute left-1/2 top-0 bottom-0 w-px bg-primary/20" />

          {/* Controls bar at top */}
          <div className="absolute top-4 left-1/2 -translate-x-1/2 pointer-events-auto flex items-center gap-2 bg-background/90 backdrop-blur-xl border border-primary/30 rounded-full px-4 py-2 shadow-2xl z-50">
            <span className="text-[9px] font-black uppercase tracking-widest text-primary mr-2">BG Edit</span>

            <Button variant="ghost" size="icon" className="h-8 w-8 text-foreground/60 hover:text-foreground" onClick={() => setEditScale((s) => Math.max(0.5, s - 0.1))} title="Zoom Out">
              <ZoomOut className="w-4 h-4" />
            </Button>
            <span className="text-[10px] font-mono font-bold text-foreground/80 w-12 text-center">{(editScale * 100).toFixed(0)}%</span>
            <Button variant="ghost" size="icon" className="h-8 w-8 text-foreground/60 hover:text-foreground" onClick={() => setEditScale((s) => Math.min(5, s + 0.1))} title="Zoom In">
              <ZoomIn className="w-4 h-4" />
            </Button>

            <div className="w-px h-5 bg-foreground/10 mx-1" />

            <span className="text-[9px] font-mono text-foreground/50">opacity</span>
            <input
              type="range" min="0" max="1" step="0.05" value={editOpacity}
              onChange={(e) => setEditOpacity(parseFloat(e.target.value))}
              className="w-20 accent-primary h-1.5"
            />
            <span className="text-[10px] font-mono font-bold text-foreground/80 w-9 text-center">{(editOpacity * 100).toFixed(0)}%</span>

            <div className="w-px h-5 bg-foreground/10 mx-1" />

            <Button variant="ghost" size="icon" className="h-8 w-8 text-foreground/60 hover:text-foreground" onClick={resetBgEdit} title="Reset">
              <RotateCcw className="w-3.5 h-3.5" />
            </Button>
            <Button variant="ghost" size="icon" className="h-8 w-8 text-red-400 hover:text-red-300 hover:bg-red-500/10" onClick={cancelBgEdit} title="Cancel">
              <X className="w-4 h-4" />
            </Button>
            <Button variant="ghost" size="icon" className="h-8 w-8 text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10" onClick={saveBgEdit} title="Save">
              <Check className="w-4 h-4" />
            </Button>
          </div>

          {/* Position info */}
          <div className="absolute bottom-4 left-1/2 -translate-x-1/2 pointer-events-none text-[9px] font-mono text-foreground/40 bg-background/60 px-3 py-1 rounded-full backdrop-blur-sm">
            pos: {editPosX.toFixed(0)}%, {editPosY.toFixed(0)}% &middot; scale: {(editScale * 100).toFixed(0)}% &middot; drag to move, scroll to zoom
          </div>
        </div>
      )}

      <header className="px-8 py-6 border-b border-foreground/5 bg-background/40 backdrop-blur-xl sticky top-0 z-10 flex items-center justify-between">
        <div className="flex items-center gap-4">
            <div className="w-1 h-8 bg-gradient-to-b from-primary to-orange-600 rounded-full shadow-[0_0_10px_var(--primary)]" />
            <div className="flex flex-col">
                <h1 className="text-xs font-black uppercase tracking-[0.3em] text-foreground/90">{profile.platformName || "Operational Command"}</h1>
                <span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest opacity-50">{profile.platformSubtitle || "Active Session"}</span>
            </div>
        </div>
        <div className="flex items-center gap-2">
            {/* Active workspace badge */}
            {activeWorkspace && (
              <a
                href={`/workspace/viewer?id=${activeWorkspace.id}`}
                className="h-9 gap-2 px-3.5 rounded-full border border-emerald-500/20 bg-emerald-500/10 text-emerald-400 flex items-center hover:bg-emerald-500/20 transition-all duration-200 cursor-pointer"
              >
                <FolderOpen className="w-3.5 h-3.5" />
                <span className="text-[10px] font-bold uppercase tracking-wider hidden sm:inline">{activeWorkspace.name}</span>
              </a>
            )}
            {/* Action buttons — pill-shaped with labels */}
            <Button
              variant="ghost"
              className="h-9 gap-2 px-3.5 rounded-full border border-foreground/10 bg-foreground/[0.03] text-muted-foreground hover:text-primary hover:bg-primary/10 hover:border-primary/20 transition-all duration-200"
              onClick={handleNewSession}
            >
              <FilePlus className="w-4 h-4" />
              <span className="text-[10px] font-bold uppercase tracking-wider hidden sm:inline">새 대화</span>
            </Button>
            <Button
              variant="ghost"
              className="h-9 gap-2 px-3.5 rounded-full border border-foreground/10 bg-foreground/[0.03] text-muted-foreground hover:text-primary hover:bg-primary/10 hover:border-primary/20 transition-all duration-200"
              onClick={() => setSessionPanelOpen(true)}
            >
              <History className="w-4 h-4" />
              <span className="text-[10px] font-bold uppercase tracking-wider hidden sm:inline">기록</span>
            </Button>
            <Button
              variant="ghost"
              className="h-9 gap-2 px-3.5 rounded-full border border-foreground/10 bg-foreground/[0.03] text-muted-foreground hover:text-purple-400 hover:bg-purple-500/10 hover:border-purple-500/20 transition-all duration-200"
              onClick={() => setMemoryPanelOpen(true)}
            >
              <Brain className="w-4 h-4" />
              <span className="text-[10px] font-bold uppercase tracking-wider hidden sm:inline">메모리</span>
            </Button>
            {chatBgImage && !bgEditMode && (
              <Button
                variant="ghost"
                className="h-9 gap-2 px-3.5 rounded-full border border-foreground/10 bg-foreground/[0.03] text-muted-foreground hover:text-foreground hover:bg-foreground/10 hover:border-foreground/20 transition-all duration-200"
                onClick={enterBgEdit}
              >
                <ImageIcon className="w-4 h-4" />
                <span className="text-[10px] font-bold uppercase tracking-wider hidden sm:inline">배경</span>
              </Button>
            )}
        </div>
      </header>

      <div className="flex-1 overflow-y-auto px-4 lg:px-8 py-10" ref={scrollRef}>
        <div className="max-w-4xl mx-auto space-y-12 pb-40">
          {messages.map((msg, idx) => {
            const text = getTextContent(msg.content);
            const images = msg._images ?? getImageUrls(msg.content);

            return (
              <div
                key={idx}
                className={cn(
                  "flex gap-4 lg:gap-6 group animate-in fade-in slide-in-from-bottom-4 duration-700",
                  msg.role === "user" ? "flex-row-reverse" : "flex-row"
                )}
              >
                <div className={cn(
                  "w-10 h-10 lg:w-12 lg:h-12 flex items-center justify-center shrink-0 rounded-2xl transition-all duration-500 shadow-xl overflow-hidden",
                  msg.role === "user"
                    ? "bg-gradient-to-br from-primary to-orange-600 text-primary-foreground shadow-primary/20 scale-95 group-hover:scale-100"
                    : "bg-foreground/5 border border-foreground/10 text-muted-foreground group-hover:bg-foreground/10"
                )}>
                  {msg.role === "user"
                    ? (profile.avatar
                      ? <img src={profile.avatar} alt="avatar" className="w-full h-full object-cover" />
                      : <User size={20} className="lg:w-5 lg:h-5" />)
                    : (profile.botAvatar
                      ? <img src={profile.botAvatar} alt="bot" className="w-full h-full object-cover" />
                      : <Bot size={20} className="lg:w-5 lg:h-5" />)
                  }
                </div>

                <div className={cn(
                  "flex flex-col gap-2 max-w-[85%] lg:max-w-[75%]",
                  msg.role === "user" ? "items-end" : "items-start"
                )}>
                  {/* ThinkingBlock for completed assistant messages */}
                  {msg.role === "assistant" && msg._thinkingSteps && msg._thinkingSteps.length > 0 && (
                    <ThinkingBlock steps={msg._thinkingSteps} isStreaming={false} />
                  )}

                  <div className={cn(
                    "relative px-6 py-4 rounded-[2rem] transition-all duration-300 shadow-2xl",
                    msg.role === "user"
                      ? "bg-primary/10 border border-primary/20 text-foreground rounded-tr-none"
                      : "bg-foreground/5 border border-foreground/5 text-foreground rounded-tl-none backdrop-blur-sm hover:bg-foreground/10"
                  )}>
                    {msg.role === "tool" && msg.name && (
                      <div className="flex items-center gap-2 font-mono text-[9px] uppercase font-black text-primary/70 mb-2 tracking-[0.2em]">
                        <Wrench size={12} />
                        <span>
                          {msg.name.includes("__")
                            ? `[${msg.name.split("__")[0]}] ${msg.name.split("__")[1]}`
                            : msg.name}
                        </span>
                      </div>
                    )}

                    {/* Attached file chips (user messages) */}
                    {msg._files && msg._files.length > 0 && (
                      <div className="flex flex-wrap gap-1.5 mb-2">
                        {msg._files.map((f, i) => (
                          <span key={i} className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-primary/10 border border-primary/20 text-[11px] font-semibold text-primary">
                            {f.isImage ? <ImageIcon className="w-3 h-3" /> : <Hammer className="w-3 h-3" />}
                            {f.name}
                          </span>
                        ))}
                      </div>
                    )}

                    {images.length > 0 && (
                      <div className="flex flex-wrap gap-2 mb-3">
                        {images.map((src, i) => (
                          <img
                            key={i}
                            src={src}
                            alt={`attached-${i}`}
                            className="max-w-[200px] max-h-[200px] rounded-xl object-cover border border-foreground/10"
                          />
                        ))}
                      </div>
                    )}

                    {(() => {
                      const displayText = (msg.role === "user" && msg._files) ? (msg._displayText || "") : text;
                      return displayText ? (
                        <div className="prose prose-sm dark:prose-invert max-w-none text-inherit leading-relaxed font-medium tracking-tight overflow-x-auto">
                          <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
                            {displayText}
                          </ReactMarkdown>
                        </div>
                      ) : null;
                    })()}
                  </div>

                  {/* Copy button & label */}
                  <div className="flex items-center gap-1 px-2">
                    {msg.role === "assistant" && text && (
                      <CopyButton text={text} />
                    )}
                    <span className="text-[9px] font-bold text-muted-foreground/30 uppercase tracking-[0.2em]">
                      {msg.role === "user" ? (profile.name || "Authorized Personnel") : (profile.botName || "AI Assistant")}
                    </span>
                  </div>

                </div>
              </div>
            );
          })}

          {/* Live streaming thinking block — shown after the last user message */}
          {isLoading && (
            <div className="flex gap-4 lg:gap-6 group animate-in fade-in slide-in-from-bottom-4 duration-700 flex-row">
              <div className="w-10 h-10 lg:w-12 lg:h-12 flex items-center justify-center shrink-0 rounded-2xl transition-all duration-500 shadow-xl bg-foreground/5 border border-foreground/10 text-muted-foreground overflow-hidden">
                {profile.botAvatar
                  ? <img src={profile.botAvatar} alt="bot" className="w-full h-full object-cover" />
                  : <Bot size={20} className="lg:w-5 lg:h-5" />}
              </div>
              <div className="flex flex-col gap-2 max-w-[85%] lg:max-w-[75%] items-start">
                {thinkingSteps.length > 0 ? (
                  <ThinkingBlock steps={thinkingSteps} isStreaming={true} />
                ) : (
                  <div className="flex items-center gap-3 px-4 py-2 bg-foreground/5 rounded-full border border-foreground/5">
                    <div className="flex gap-1.5">
                      <div className="w-1 h-1 bg-primary rounded-full animate-bounce [animation-delay:-0.3s]" />
                      <div className="w-1 h-1 bg-primary rounded-full animate-bounce [animation-delay:-0.15s]" />
                      <div className="w-1 h-1 bg-primary rounded-full animate-bounce" />
                    </div>
                    <span className="text-[9px] font-black text-primary/60 uppercase tracking-widest">Processing Logic...</span>
                  </div>
                )}
                <div className="px-2 text-[9px] font-bold text-muted-foreground/30 uppercase tracking-[0.2em]">
                  {profile.botName || "AI Assistant"}
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Hidden file input */}
      <input
        ref={fileInputRef}
        type="file"
        accept="*/*"
        multiple
        onChange={handleFileSelect}
        className="hidden"
      />

      {/* MCP Tools Panel */}
      <MCPToolsPanel open={mcpPanelOpen} onOpenChange={setMcpPanelOpen} />

      {/* Session Panel */}
      <SessionPanel
        open={sessionPanelOpen}
        onOpenChange={setSessionPanelOpen}
        currentSessionId={currentSessionId}
        onSelectSession={handleSelectSession}
        onNewSession={handleNewSession}
      />

      {/* Memory Panel */}
      <MemoryPanel
        open={memoryPanelOpen}
        onOpenChange={setMemoryPanelOpen}
      />

      <div className="absolute bottom-0 left-0 right-0 p-6 lg:p-10 pointer-events-none">
        <div className="max-w-4xl mx-auto pointer-events-auto">
          <div className="relative group">
            {/* Glow Effect */}
            <div className="absolute -inset-1 bg-gradient-to-r from-primary/20 to-orange-600/20 blur-xl opacity-0 group-focus-within:opacity-100 transition duration-1000" />

            <div className="relative bg-background/60 backdrop-blur-2xl rounded-[2.5rem] border border-foreground/10 shadow-2xl transition-all duration-300 focus-within:border-primary/50 focus-within:shadow-[0_0_40px_-10px_rgba(245,158,11,0.2)]">
              {/* File preview chips */}
              {attachedFiles.length > 0 && (
                <div className="pt-3">
                  <FilePreviewChips files={attachedFiles} onRemove={removeFile} />
                </div>
              )}

              <div className="flex items-center gap-2 p-2 pl-4">
                {/* + button for file attach */}
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  onClick={() => fileInputRef.current?.click()}
                  className="h-10 w-10 rounded-full text-muted-foreground/50 hover:text-foreground hover:bg-foreground/10 transition-colors shrink-0"
                >
                  <Plus className="w-5 h-5" />
                </Button>

                {/* MCP tools button */}
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  onClick={() => setMcpPanelOpen(true)}
                  className="h-10 w-10 rounded-full text-muted-foreground/50 hover:text-foreground hover:bg-foreground/10 transition-colors shrink-0"
                >
                  <Hammer className="w-4 h-4" />
                </Button>

                <textarea
                  ref={textareaRef}
                  placeholder="TRANSMIT SYSTEM COMMAND..."
                  value={input}
                  onChange={(e) => {
                    setInput(e.target.value);
                    // Auto-resize
                    e.target.style.height = "auto";
                    e.target.style.height = Math.min(e.target.scrollHeight, 200) + "px";
                  }}
                  onKeyDown={(e) => {
                    if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
                      e.preventDefault();
                      handleSend();
                    }
                  }}
                  onPaste={handlePaste}
                  rows={1}
                  className="flex-1 border-none bg-transparent min-h-[3.5rem] max-h-[200px] py-4 text-sm font-bold tracking-tight focus-visible:outline-none placeholder:text-muted-foreground/20 placeholder:uppercase resize-none overflow-y-auto"
                />
                {isLoading ? (
                  <Button
                    onClick={handleStop}
                    className="h-14 w-14 rounded-full bg-red-500/80 hover:bg-red-500 text-white shadow-lg shadow-red-500/20 hover:scale-105 active:scale-95 transition-all duration-300"
                  >
                    <Square className="w-5 h-5 fill-current" />
                  </Button>
                ) : (
                  <Button
                    onClick={handleSend}
                    disabled={!input.trim() && attachedFiles.length === 0}
                    className="h-14 w-14 rounded-full bg-gradient-to-br from-primary to-orange-600 text-primary-foreground shadow-lg shadow-primary/20 hover:scale-105 active:scale-95 transition-all duration-300"
                  >
                    <Send className="w-5 h-5" />
                  </Button>
                )}
              </div>
            </div>
          </div>
          <div className="flex justify-between items-center mt-6 px-8">
              <span className="text-[9px] font-black text-muted-foreground/20 uppercase tracking-[0.3em]">Operational Access Restricted</span>
              <div className="flex items-center gap-4">
                  <span className="text-[9px] font-black text-primary/40 uppercase tracking-[0.3em]">Biometric Sync Active</span>
                  <div className="h-1 w-12 bg-foreground/5 rounded-full overflow-hidden">
                      <div className="h-full w-2/3 bg-primary/30" />
                  </div>
              </div>
          </div>
        </div>
      </div>
    </div>
  );
}
