"use client";

import { useState, useRef, useEffect, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
  Send, Sparkles, TrendingUp, Shield, PieChart,
  Zap, Copy, ThumbsUp, ThumbsDown, Trash2, Mic,
  Paperclip, FileText, ImageIcon, X, Upload,
  CheckCircle2, AlertTriangle, ChevronDown, ChevronUp,
  FileSpreadsheet, File,
} from "lucide-react";
import { aiApi, memoryApi, documentsApi } from "@/lib/api";
import { useAuthStore } from "@/lib/stores/authStore";
import { useLanguageStore } from "@/lib/stores/languageStore";
import { useThemeStore } from "@/lib/stores/themeStore";

// ─── Types ────────────────────────────────────────────────────────────────────
interface AttachedFile {
  file: File;
  previewUrl?: string;         // for images
  status: "pending" | "uploading" | "done" | "error";
  docId?: string;              // backend document id after upload
  summary?: string;
  insights?: string[];
  errorMsg?: string;
}

interface Message {
  id: string;
  role: "user" | "assistant";
  content: string;
  streaming?: boolean;
  timestamp: Date;
  // doc context attached to this user message
  attachments?: Array<{
    name: string;
    fileType: string;
    docId: string;
    summary?: string;
    insights?: string[];
  }>;
  // if this was a doc-context answer
  docMode?: boolean;
}

// ─── Accepted types ───────────────────────────────────────────────────────────
const ACCEPTED = ".pdf,.docx,.txt,.csv,.png,.jpg,.jpeg,.webp";
const IMAGE_TYPES = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
const DOC_TYPES   = [
  "application/pdf",
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "text/plain",
  "text/csv",
];

// ─── Suggestions per language ─────────────────────────────────────────────────
const SUGGESTIONS = {
  en: [
    { icon: TrendingUp, label: "What's my total balance?",       color: "text-emerald-400", bg: "bg-emerald-500/10 border-emerald-500/20" },
    { icon: PieChart,   label: "Analyze my spending this month",  color: "text-blue-400",    bg: "bg-blue-500/10 border-blue-500/20" },
    { icon: Shield,     label: "Explain my fraud alerts",         color: "text-purple-400",  bg: "bg-purple-500/10 border-purple-500/20" },
    { icon: Zap,        label: "Give me a savings nudge",         color: "text-amber-400",   bg: "bg-amber-500/10 border-amber-500/20" },
  ],
  hi: [
    { icon: TrendingUp, label: "मेरा कुल बैलेंस क्या है?",        color: "text-emerald-400", bg: "bg-emerald-500/10 border-emerald-500/20" },
    { icon: PieChart,   label: "इस महीने मेरा खर्च विश्लेषण करें",  color: "text-blue-400",    bg: "bg-blue-500/10 border-blue-500/20" },
    { icon: Shield,     label: "मेरे फ्रॉड अलर्ट समझाएं",          color: "text-purple-400",  bg: "bg-purple-500/10 border-purple-500/20" },
    { icon: Zap,        label: "बचत के लिए सुझाव दें",             color: "text-amber-400",   bg: "bg-amber-500/10 border-amber-500/20" },
  ],
  mr: [
    { icon: TrendingUp, label: "माझी एकूण शिल्लक किती आहे?",      color: "text-emerald-400", bg: "bg-emerald-500/10 border-emerald-500/20" },
    { icon: PieChart,   label: "या महिन्याचा खर्च विश्लेषण करा",   color: "text-blue-400",    bg: "bg-blue-500/10 border-blue-500/20" },
    { icon: Shield,     label: "माझे फसवणूक अलर्ट सांगा",          color: "text-purple-400",  bg: "bg-purple-500/10 border-purple-500/20" },
    { icon: Zap,        label: "बचतीसाठी सल्ला द्या",              color: "text-amber-400",   bg: "bg-amber-500/10 border-amber-500/20" },
  ],
};

// ─── File icon helper ─────────────────────────────────────────────────────────
function FileIcon({ type, className }: { type: string; className?: string }) {
  if (IMAGE_TYPES.includes(type))    return <ImageIcon className={className} />;
  if (type === "text/csv")            return <FileSpreadsheet className={className} />;
  if (type.includes("pdf"))          return <FileText className={className} />;
  return <File className={className} />;
}

function fileTypeLabel(type: string, name: string): string {
  const ext = name.split(".").pop()?.toUpperCase() ?? "FILE";
  if (IMAGE_TYPES.includes(type)) return "IMAGE";
  return ext;
}

function formatBytes(b: number) {
  if (b < 1024) return `${b} B`;
  if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;
  return `${(b / (1024 * 1024)).toFixed(1)} MB`;
}

// ─── AI Orb ───────────────────────────────────────────────────────────────────
function AIOrb({ isThinking }: { isThinking: boolean }) {
  return (
    <div className="relative flex items-center justify-center">
      <motion.div
        animate={{ scale: isThinking ? [1,1.3,1] : [1,1.1,1], opacity: isThinking ? [0.3,0.6,0.3] : [0.2,0.4,0.2] }}
        transition={{ duration: isThinking ? 0.8 : 3, repeat: Infinity, ease: "easeInOut" }}
        className="absolute h-24 w-24 rounded-full border border-emerald-500/30"
      />
      <motion.div
        animate={{ scale: isThinking ? [1,1.5,1] : [1,1.15,1], opacity: isThinking ? [0.2,0.4,0.2] : [0.1,0.2,0.1] }}
        transition={{ duration: isThinking ? 0.8 : 3, repeat: Infinity, ease: "easeInOut", delay: 0.2 }}
        className="absolute h-32 w-32 rounded-full border border-blue-500/20"
      />
      <motion.div
        animate={{
          boxShadow: isThinking
            ? ["0 0 20px rgba(16,185,129,0.6),0 0 60px rgba(59,130,246,0.4)","0 0 40px rgba(16,185,129,0.8),0 0 80px rgba(59,130,246,0.5)","0 0 20px rgba(16,185,129,0.6),0 0 60px rgba(59,130,246,0.4)"]
            : ["0 0 20px rgba(16,185,129,0.3),0 0 40px rgba(59,130,246,0.2)","0 0 30px rgba(16,185,129,0.5),0 0 60px rgba(59,130,246,0.3)","0 0 20px rgba(16,185,129,0.3),0 0 40px rgba(59,130,246,0.2)"],
        }}
        transition={{ duration: isThinking ? 0.8 : 3, repeat: Infinity, ease: "easeInOut" }}
        className="relative h-16 w-16 rounded-full bg-gradient-to-br from-emerald-400 via-cyan-400 to-blue-500 flex items-center justify-center"
      >
        <motion.div animate={{ rotate: isThinking ? 360 : 0 }} transition={{ duration: 2, repeat: isThinking ? Infinity : 0, ease: "linear" }}>
          <Sparkles className="h-7 w-7 text-white" />
        </motion.div>
      </motion.div>
    </div>
  );
}

// ─── Attachment Card (inside input area) ─────────────────────────────────────
function AttachmentChip({ file, onRemove, isLight }: { file: AttachedFile; onRemove: () => void; isLight: boolean }) {
  const isImg = IMAGE_TYPES.includes(file.file.type);
  return (
    <motion.div
      initial={{ opacity: 0, scale: 0.85 }}
      animate={{ opacity: 1, scale: 1 }}
      exit={{ opacity: 0, scale: 0.85 }}
      className={`relative flex items-center gap-2 rounded-xl border px-3 py-2 text-xs max-w-[200px] ${
        isLight ? "bg-slate-50 border-slate-200" : "bg-white/8 border-white/10"
      }`}
    >
      {/* Status indicator */}
      {file.status === "uploading" && (
        <motion.div
          animate={{ rotate: 360 }}
          transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
          className="h-4 w-4 border-2 border-emerald-500 border-t-transparent rounded-full flex-shrink-0"
        />
      )}
      {file.status === "done" && <CheckCircle2 className="h-4 w-4 text-emerald-500 flex-shrink-0" />}
      {file.status === "error" && <AlertTriangle className="h-4 w-4 text-red-500 flex-shrink-0" />}
      {file.status === "pending" && (
        isImg
          ? <ImageIcon className="h-4 w-4 text-blue-400 flex-shrink-0" />
          : <FileText className="h-4 w-4 text-purple-400 flex-shrink-0" />
      )}

      {/* Preview thumb for images */}
      {isImg && file.previewUrl && (
        // eslint-disable-next-line @next/next/no-img-element
        <img src={file.previewUrl} alt="preview" className="h-6 w-6 rounded object-cover flex-shrink-0" />
      )}

      <span className="truncate font-medium" style={{ color: "var(--fg)", maxWidth: 100 }}>
        {file.file.name}
      </span>
      <span style={{ color: "var(--fg-subtle)" }}>{formatBytes(file.file.size)}</span>

      {file.status !== "uploading" && (
        <button
          onClick={onRemove}
          className="ml-auto flex-shrink-0 rounded-full p-0.5 hover:bg-red-500/10 transition-colors"
        >
          <X className="h-3 w-3 text-red-400" />
        </button>
      )}
    </motion.div>
  );
}

// ─── Document Badge (in message bubble) ──────────────────────────────────────
function DocBadge({
  name, fileType, summary, insights, isLight,
}: {
  name: string;
  fileType: string;
  summary?: string;
  insights?: string[];
  isLight: boolean;
}) {
  const [expanded, setExpanded] = useState(false);
  const isImg = ["png", "jpg", "jpeg", "webp"].includes(fileType.toLowerCase());

  return (
    <div
      className={`rounded-xl border text-xs overflow-hidden ${
        isLight ? "bg-purple-50 border-purple-200/80" : "bg-purple-500/10 border-purple-500/20"
      }`}
    >
      <div className="flex items-center gap-2 px-3 py-2">
        {isImg
          ? <ImageIcon className="h-3.5 w-3.5 text-purple-500 flex-shrink-0" />
          : <FileText className="h-3.5 w-3.5 text-purple-500 flex-shrink-0" />}
        <span className="font-semibold text-purple-600 truncate flex-1">{name}</span>
        <span className={`px-1.5 py-0.5 rounded text-[9px] font-bold uppercase ${
          isLight ? "bg-purple-100 text-purple-600" : "bg-purple-500/20 text-purple-400"
        }`}>
          {fileType.toUpperCase()}
        </span>
        {(summary || (insights && insights.length > 0)) && (
          <button
            onClick={() => setExpanded(v => !v)}
            className="text-purple-500 ml-1"
          >
            {expanded ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
          </button>
        )}
      </div>
      <AnimatePresence>
        {expanded && (summary || (insights && insights.length > 0)) && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: "auto", opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.2 }}
            className={`border-t px-3 py-2 space-y-1.5 ${
              isLight ? "border-purple-200/80" : "border-purple-500/20"
            }`}
          >
            {summary && (
              <p style={{ color: "var(--fg-muted)" }}>{summary}</p>
            )}
            {insights && insights.length > 0 && (
              <ul className="space-y-0.5">
                {insights.map((ins, i) => (
                  <li key={i} className="flex gap-1.5" style={{ color: "var(--fg-muted)" }}>
                    <span className="text-purple-500 flex-shrink-0">•</span>
                    <span>{ins}</span>
                  </li>
                ))}
              </ul>
            )}
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}

// ─── Message Bubble ───────────────────────────────────────────────────────────
function MessageBubble({
  message, onCopy, userInitial, isLight,
}: {
  message: Message;
  onCopy: (t: string) => void;
  userInitial: string;
  isLight: boolean;
}) {
  const isUser = message.role === "user";

  const renderContent = (text: string) =>
    text.split("\n").map((line, i) => {
      if (line.startsWith("**") && line.endsWith("**"))
        return <p key={i} className="font-semibold" style={{ color: "var(--fg)" }}>{line.slice(2, -2)}</p>;
      if (line.startsWith("- "))
        return <p key={i} className="ml-2" style={{ color: "var(--fg-muted)" }}>• {line.slice(2)}</p>;
      if (line.startsWith("# "))
        return <p key={i} className="font-bold text-base mt-1" style={{ color: "var(--fg)" }}>{line.slice(2)}</p>;
      return (
        <p key={i} className={line === "" ? "h-2" : ""} style={{ color: isUser ? "white" : "var(--fg-muted)" }}>
          {line}
        </p>
      );
    });

  return (
    <motion.div
      initial={{ opacity: 0, y: 10, scale: 0.98 }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      transition={{ duration: 0.3, ease: "easeOut" }}
      className={`flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"}`}
    >
      {/* Avatar */}
      <div className={`flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-xl text-xs font-bold ${
        isUser
          ? "bg-gradient-to-br from-blue-500 to-purple-600 text-white"
          : "bg-gradient-to-br from-emerald-400 to-cyan-500"
      }`}>
        {isUser ? userInitial : <Sparkles className="h-4 w-4 text-white" />}
      </div>

      {/* Content */}
      <div className={`max-w-[78%] flex flex-col gap-2 ${isUser ? "items-end" : "items-start"}`}>
        {/* Attachment badges (user side) */}
        {isUser && message.attachments && message.attachments.length > 0 && (
          <div className="flex flex-col gap-1.5 w-full">
            {message.attachments.map((att) => (
              <DocBadge
                key={att.docId}
                name={att.name}
                fileType={att.fileType}
                summary={att.summary}
                insights={att.insights}
                isLight={isLight}
              />
            ))}
          </div>
        )}

        {/* Doc-mode label on AI answer */}
        {!isUser && message.docMode && (
          <div className="flex items-center gap-1.5 text-[10px] text-purple-500">
            <FileText className="h-3 w-3" />
            Document Analysis
          </div>
        )}

        {/* Bubble */}
        {message.content && (
          <div className={`rounded-2xl px-4 py-3 text-sm leading-relaxed ${
            isUser
              ? "bg-gradient-to-br from-blue-600 to-blue-700 text-white rounded-tr-sm"
              : isLight
                ? "bg-white border border-slate-200 rounded-tl-sm"
                : "glass border border-white/10 rounded-tl-sm"
          }`}>
            <div className="whitespace-pre-wrap">{renderContent(message.content)}</div>
            {message.streaming && <span className="streaming-cursor" />}
          </div>
        )}

        {/* Action row for AI messages */}
        {!isUser && !message.streaming && message.content && (
          <div className="flex items-center gap-1 px-1">
            {[
              { icon: Copy,       label: "Copy",  action: () => onCopy(message.content) },
              { icon: ThumbsUp,   label: "Good",  action: () => {} },
              { icon: ThumbsDown, label: "Bad",   action: () => {} },
            ].map(({ icon: Icon, label, action }) => (
              <button
                key={label} title={label} onClick={action}
                className="p-1 rounded-lg transition-all hover:bg-white/5"
                style={{ color: "var(--fg-subtle)" }}
              >
                <Icon className="h-3 w-3" />
              </button>
            ))}
          </div>
        )}
      </div>
    </motion.div>
  );
}

// ─── Main Chat Page ───────────────────────────────────────────────────────────
export default function ChatPage() {
  const { user }          = useAuthStore();
  const { language, t }   = useLanguageStore();
  const { theme }         = useThemeStore();
  const isLight           = theme === "light";
  const userInitial       = user?.name?.charAt(0).toUpperCase() ?? "U";
  const suggestions       = SUGGESTIONS[language as keyof typeof SUGGESTIONS] ?? SUGGESTIONS.en;

  const [sessionId, setSessionId] = useState<string | null>(() =>
    typeof window !== "undefined" ? localStorage.getItem("bb_chat_session") : null
  );
  const [messages,       setMessages]       = useState<Message[]>([]);
  const [historyLoaded,  setHistoryLoaded]  = useState(false);
  const [input,          setInput]          = useState("");
  const [isThinking,     setIsThinking]     = useState(false);
  const [attachedFiles,  setAttachedFiles]  = useState<AttachedFile[]>([]);
  const [isDragging,     setIsDragging]     = useState(false);

  const inputRef       = useRef<HTMLTextAreaElement>(null);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const fileInputRef   = useRef<HTMLInputElement>(null);
  const abortRef       = useRef<AbortController | null>(null);

  // Auto-scroll
  useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]);

  // Load history on mount
  useEffect(() => {
    if (historyLoaded) return;
    const load = async () => {
      try {
        const res = await memoryApi.history(sessionId ?? undefined);
        if (res.messages.length > 0) {
          setMessages(res.messages.map((m) => ({
            id: m.id,
            role: m.role as "user" | "assistant",
            content: m.content,
            timestamp: new Date(m.created_at),
          })));
          if (res.messages[0].session_id) {
            setSessionId(res.messages[0].session_id);
            localStorage.setItem("bb_chat_session", res.messages[0].session_id);
          }
        } else {
          setMessages([{
            id: "welcome",
            role: "assistant",
            content:
              language === "hi"
                ? "नमस्ते! मैं आपका AI वित्तीय सहायक हूँ। आप बैंक स्टेटमेंट, इनवॉइस, CSV या कोई भी दस्तावेज़ अटैच करके उसके बारे में पूछ सकते हैं।\n\nआज आप क्या जानना चाहते हैं?"
                : language === "mr"
                ? "नमस्कार! मी तुमचा AI आर्थिक सहाय्यक आहे. बँक स्टेटमेंट, इनव्हॉइस किंवा कोणतेही कागदपत्र अटॅच करा आणि प्रश्न विचारा.\n\nआज तुम्हाला काय जाणून घ्यायचे आहे?"
                : "Hello! I'm your AI financial assistant.\n\nYou can **attach files** (PDF, DOCX, CSV, images) directly here and ask me anything about them — bank statements, invoices, contracts, and more.\n\nWhat would you like to explore today?",
            timestamp: new Date(),
          }]);
        }
      } catch {
        setMessages([{
          id: "welcome",
          role: "assistant",
          content: "Hello! I'm your AI financial assistant. Attach any document and ask me about it, or ask about your finances.",
          timestamp: new Date(),
        }]);
      }
      setHistoryLoaded(true);
    };
    load();
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // ── Upload a single file → returns docId + analysis ──────────────────────
  const uploadFile = useCallback(async (af: AttachedFile): Promise<AttachedFile> => {
    try {
      setAttachedFiles((prev) =>
        prev.map((f) => f.file === af.file ? { ...f, status: "uploading" } : f)
      );
      const result = await documentsApi.upload(af.file, language);
      const updated: AttachedFile = {
        ...af,
        status: "done",
        docId: result.id,
        summary: result.summary,
        insights: result.insights,
      };
      setAttachedFiles((prev) =>
        prev.map((f) => f.file === af.file ? updated : f)
      );
      return updated;
    } catch (err) {
      const updated: AttachedFile = {
        ...af,
        status: "error",
        errorMsg: (err as Error).message || "Upload failed",
      };
      setAttachedFiles((prev) =>
        prev.map((f) => f.file === af.file ? updated : f)
      );
      return updated;
    }
  }, [language]);

  // ── Add files (from input or drop) ───────────────────────────────────────
  const addFiles = useCallback((files: FileList | File[]) => {
    const arr = Array.from(files);
    const valid = arr.filter((f) => {
      const ok = [...IMAGE_TYPES, ...DOC_TYPES].includes(f.type) ||
        ["pdf","docx","txt","csv","png","jpg","jpeg","webp"].some(ext =>
          f.name.toLowerCase().endsWith(`.${ext}`)
        );
      return ok && f.size <= 10 * 1024 * 1024;
    });
    if (valid.length === 0) return;

    const newFiles: AttachedFile[] = valid.map((f) => ({
      file: f,
      previewUrl: IMAGE_TYPES.includes(f.type) ? URL.createObjectURL(f) : undefined,
      status: "pending",
    }));

    setAttachedFiles((prev) => {
      const updated = [...prev, ...newFiles];
      // Kick off uploads immediately
      newFiles.forEach((af) => {
        // slight delay so state settles
        setTimeout(() => uploadFile(af), 100);
      });
      return updated;
    });
  }, [uploadFile]);

  // ── Drag-and-drop ─────────────────────────────────────────────────────────
  const handleDragOver  = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); };
  const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); };
  const handleDrop      = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
    if (e.dataTransfer.files.length) addFiles(e.dataTransfer.files);
  };

  // ── Streaming word-by-word ───────────────────────────────────────────────
  const streamWords = useCallback((msgId: string, fullText: string) => {
    const words = fullText.split(" ");
    let i = 0;
    setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, streaming: true } : m));
    const interval = setInterval(() => {
      if (i >= words.length) {
        clearInterval(interval);
        setMessages((prev) => prev.map((m) => m.id === msgId ? { ...m, streaming: false } : m));
        return;
      }
      setMessages((prev) =>
        prev.map((m) => m.id === msgId ? { ...m, content: words.slice(0, i + 1).join(" ") } : m)
      );
      i++;
    }, 28);
  }, []);

  // ── Send message ─────────────────────────────────────────────────────────
  const sendMessage = useCallback(async (text?: string) => {
    const content = (text ?? input).trim();

    // Need either text or a completed doc
    const doneDocs = attachedFiles.filter((f) => f.status === "done" && f.docId);
    if (!content && doneDocs.length === 0) return;
    if (isThinking) return;

    abortRef.current?.abort();
    abortRef.current = new AbortController();
    setInput("");
    setIsThinking(true);

    // Build user message
    const userMsg: Message = {
      id: `user-${Date.now()}`,
      role: "user",
      content,
      timestamp: new Date(),
      attachments: doneDocs.map((f) => ({
        name: f.file.name,
        fileType: f.file.name.split(".").pop() ?? "file",
        docId: f.docId!,
        summary: f.summary,
        insights: f.insights,
      })),
    };
    setMessages((prev) => [...prev, userMsg]);

    // Clear attached files after sending
    setAttachedFiles([]);

    const aiId = `ai-${Date.now()}`;
    setMessages((prev) => [
      ...prev,
      { id: aiId, role: "assistant", content: "", streaming: true, timestamp: new Date(), docMode: doneDocs.length > 0 },
    ]);

    try {
      let responseText = "";

      if (doneDocs.length > 0) {
        // ── Document Q&A mode ────────────────────────────────────────────
        const doc = doneDocs[0]; // use first doc for Q&A
        const question = content ||
          (language === "hi" ? "इस दस्तावेज़ का सारांश और मुख्य जानकारी बताएं।"
          : language === "mr" ? "या कागदपत्राचा सारांश आणि मुख्य माहिती सांगा."
          : "Please summarize this document and give me the key financial insights.");

        const res = await documentsApi.chat(doc.docId!, question, language);
        responseText = res.answer;

        // If multiple docs, answer about remaining ones too
        for (const extraDoc of doneDocs.slice(1)) {
          const extra = await documentsApi.chat(
            extraDoc.docId!,
            question,
            language
          );
          responseText += `\n\n---\n**${extraDoc.file.name}:**\n${extra.answer}`;
        }
      } else {
        // ── Regular financial chat ────────────────────────────────────────
        const res = await aiApi.chat(content, user?.user_id, sessionId ?? undefined, language);
        responseText = res.response;
      }

      setIsThinking(false);
      streamWords(aiId, responseText);

      // Persist to memory
      const msgContent = content || (doneDocs.map(d => `[Document: ${d.file.name}]`).join(", "));
      const sid = sessionId;
      const savedUser = await memoryApi.save({
        session_id: sid ?? undefined,
        role: "user",
        content: msgContent,
        session_title: msgContent.slice(0, 40),
      });
      const newSid = savedUser.session_id;
      if (newSid && newSid !== sessionId) {
        setSessionId(newSid);
        localStorage.setItem("bb_chat_session", newSid);
      }
      await memoryApi.save({ session_id: newSid ?? undefined, role: "assistant", content: responseText });

    } catch (err) {
      setIsThinking(false);
      const errMsg =
        (err as Error).message === "Session expired. Please log in again."
          ? "Session expired. Please refresh and log in again."
          : "⚠️ Could not reach the AI backend. Please try again.";
      setMessages((prev) =>
        prev.map((m) => m.id === aiId ? { ...m, content: errMsg, streaming: false } : m)
      );
    }
  }, [input, isThinking, attachedFiles, user?.user_id, sessionId, streamWords, language]);

  const clearHistory = async () => {
    try {
      await memoryApi.clear(sessionId ?? undefined);
      setSessionId(null);
      setAttachedFiles([]);
      localStorage.removeItem("bb_chat_session");
      setMessages([{
        id: "welcome",
        role: "assistant",
        content: "Chat history cleared. How can I help you?",
        timestamp: new Date(),
      }]);
    } catch { /* ignore */ }
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); }
  };

  const isStreaming    = messages.some((m) => m.streaming);
  const hasUploading   = attachedFiles.some((f) => f.status === "uploading");
  const hasDone        = attachedFiles.some((f) => f.status === "done");
  const canSend        = (input.trim() || hasDone) && !isThinking && !isStreaming && !hasUploading;

  const headerBg = isLight ? "bg-white/90 border-black/8" : "bg-black/20 border-white/10";
  const inputBg  = isLight ? "bg-white/90 border-black/8" : "bg-black/20 border-white/10";

  return (
    <div
      className="flex h-[calc(100vh-4rem)] flex-col -m-8"
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
    >
      {/* ── Drag overlay ───────────────────────────────────────────────────── */}
      <AnimatePresence>
        {isDragging && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="absolute inset-0 z-50 flex flex-col items-center justify-center rounded-2xl border-2 border-dashed border-emerald-500 bg-emerald-500/10 backdrop-blur-sm pointer-events-none"
          >
            <Upload className="h-12 w-12 text-emerald-500 mb-3" />
            <p className="text-lg font-semibold text-emerald-500">Drop files here</p>
            <p className="text-sm text-emerald-400 mt-1">PDF, DOCX, CSV, TXT, Images — max 10 MB</p>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Header ─────────────────────────────────────────────────────────── */}
      <div
        className={`flex items-center justify-between border-b backdrop-blur-xl px-6 py-3 flex-shrink-0 ${headerBg}`}
      >
        <div className="flex items-center gap-3">
          <div className="flex items-center gap-2">
            <div className="h-1.5 w-1.5 rounded-full bg-emerald-400 animate-pulse" />
            <span className="text-xs text-emerald-500">Live AI · {language.toUpperCase()}</span>
          </div>
          <div className="h-4 w-px" style={{ background: "var(--border-strong)" }} />
          <div>
            <h1 className="text-sm font-semibold" style={{ color: "var(--fg)" }}>BankBot AI Assistant</h1>
            <p className="text-[10px]" style={{ color: "var(--fg-subtle)" }}>
              Context-aware · Document analysis · Memory enabled
            </p>
          </div>
        </div>

        <div className="flex items-center gap-2">
          {/* Upload shortcut */}
          <motion.button
            whileHover={{ scale: 1.04 }}
            whileTap={{ scale: 0.96 }}
            onClick={() => fileInputRef.current?.click()}
            title="Attach file"
            className={`flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs font-medium transition-colors ${
              isLight
                ? "border-purple-200 bg-purple-50 text-purple-600 hover:bg-purple-100"
                : "border-purple-500/30 bg-purple-500/10 text-purple-400 hover:bg-purple-500/20"
            }`}
          >
            <Paperclip className="h-3.5 w-3.5" />
            Attach
          </motion.button>

          <button
            onClick={clearHistory}
            title="Clear history"
            className="flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs transition-colors"
            style={{ borderColor: "var(--border)", color: "var(--fg-subtle)" }}
          >
            <Trash2 className="h-3.5 w-3.5" />
            Clear
          </button>
        </div>
      </div>

      {/* ── Messages ───────────────────────────────────────────────────────── */}
      <div className="flex-1 overflow-y-auto px-6 py-5 space-y-5">

        {/* Welcome screen */}
        {messages.length === 1 && messages[0].id === "welcome" && (
          <motion.div
            initial={{ opacity: 0, scale: 0.8 }}
            animate={{ opacity: 1, scale: 1 }}
            transition={{ duration: 0.6 }}
            className="flex flex-col items-center gap-6 py-6"
          >
            <AIOrb isThinking={false} />
            <div className="text-center">
              <p className="text-lg font-semibold" style={{ color: "var(--fg)" }}>
                Your AI Financial Twin
              </p>
              <p className="text-sm mt-1" style={{ color: "var(--fg-muted)" }}>
                {t("chat_placeholder")}
              </p>
            </div>

            {/* File type shortcuts */}
            <div className="flex gap-3 flex-wrap justify-center">
              {[
                { icon: FileText,        label: "Bank Statement", ext: ".pdf",  color: "text-blue-400",   bg: isLight ? "bg-blue-50 border-blue-200" : "bg-blue-500/10 border-blue-500/20" },
                { icon: FileSpreadsheet, label: "CSV / Excel",    ext: ".csv",  color: "text-emerald-400", bg: isLight ? "bg-emerald-50 border-emerald-200" : "bg-emerald-500/10 border-emerald-500/20" },
                { icon: FileText,        label: "Invoice / Doc",  ext: ".docx", color: "text-purple-400", bg: isLight ? "bg-purple-50 border-purple-200" : "bg-purple-500/10 border-purple-500/20" },
                { icon: ImageIcon,       label: "Statement Image",ext: ".png",  color: "text-amber-400",  bg: isLight ? "bg-amber-50 border-amber-200" : "bg-amber-500/10 border-amber-500/20" },
              ].map((item) => (
                <motion.button
                  key={item.label}
                  whileHover={{ scale: 1.04 }}
                  whileTap={{ scale: 0.96 }}
                  onClick={() => fileInputRef.current?.click()}
                  className={`flex items-center gap-2 rounded-xl border px-3 py-2 text-xs font-medium transition-all ${item.bg} ${item.color}`}
                >
                  <item.icon className="h-3.5 w-3.5" />
                  {item.label}
                </motion.button>
              ))}
            </div>

            {/* Standard suggestions */}
            <div className="grid grid-cols-2 gap-2.5 w-full max-w-md">
              {suggestions.map((s) => {
                const Icon = s.icon;
                return (
                  <motion.button
                    key={s.label}
                    whileHover={{ scale: 1.03 }}
                    whileTap={{ scale: 0.97 }}
                    onClick={() => sendMessage(s.label)}
                    className={`flex items-center gap-2 rounded-xl border px-3 py-2.5 text-sm font-medium transition-all ${s.bg} ${s.color} hover:brightness-110`}
                  >
                    <Icon className="h-4 w-4 flex-shrink-0" />
                    <span className="text-left text-xs leading-snug">{s.label}</span>
                  </motion.button>
                );
              })}
            </div>
          </motion.div>
        )}

        {/* Message list */}
        {messages.map((msg) => (
          <MessageBubble
            key={msg.id}
            message={msg}
            onCopy={(t) => navigator.clipboard.writeText(t).catch(() => {})}
            userInitial={userInitial}
            isLight={isLight}
          />
        ))}

        {/* Thinking indicator */}
        <AnimatePresence>
          {isThinking && (
            <motion.div
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="flex gap-3"
            >
              <div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-emerald-400 to-cyan-500">
                <Sparkles className="h-4 w-4 text-white" />
              </div>
              <div className={`rounded-2xl rounded-tl-sm px-4 py-3 border ${
                isLight ? "bg-white border-slate-200" : "glass border-white/10"
              }`}>
                <div className="flex gap-1 items-center h-4">
                  {[0, 1, 2].map((i) => (
                    <motion.div
                      key={i}
                      animate={{ y: [0, -4, 0] }}
                      transition={{ duration: 0.6, repeat: Infinity, delay: i * 0.15 }}
                      className="h-1.5 w-1.5 rounded-full bg-emerald-400"
                    />
                  ))}
                </div>
              </div>
            </motion.div>
          )}
        </AnimatePresence>

        <div ref={messagesEndRef} />
      </div>

      {/* ── Quick suggestions (post-first-message) ─────────────────────────── */}
      {messages.length > 1 && (
        <div className="flex gap-2 px-6 pb-2 overflow-x-auto flex-shrink-0">
          {suggestions.map((s) => {
            const Icon = s.icon;
            return (
              <button
                key={s.label}
                onClick={() => sendMessage(s.label)}
                disabled={isStreaming || isThinking}
                className={`flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs font-medium whitespace-nowrap transition-all disabled:opacity-40 ${s.bg} ${s.color} hover:brightness-110`}
              >
                <Icon className="h-3 w-3" />
                {s.label}
              </button>
            );
          })}
        </div>
      )}

      {/* ── Input area ─────────────────────────────────────────────────────── */}
      <div className={`flex-shrink-0 border-t backdrop-blur-xl px-6 py-3 ${inputBg}`}>

        {/* Attached files preview */}
        <AnimatePresence>
          {attachedFiles.length > 0 && (
            <motion.div
              initial={{ opacity: 0, height: 0 }}
              animate={{ opacity: 1, height: "auto" }}
              exit={{ opacity: 0, height: 0 }}
              className="flex flex-wrap gap-2 mb-3"
            >
              {attachedFiles.map((af, i) => (
                <AttachmentChip
                  key={i}
                  file={af}
                  isLight={isLight}
                  onRemove={() => {
                    if (af.previewUrl) URL.revokeObjectURL(af.previewUrl);
                    setAttachedFiles((prev) => prev.filter((_, idx) => idx !== i));
                  }}
                />
              ))}
            </motion.div>
          )}
        </AnimatePresence>

        {/* Input row */}
        <div
          className={`flex items-end gap-2 rounded-2xl border px-3 py-2.5 transition-all focus-within:border-emerald-500/50 ${
            isLight ? "border-slate-200 bg-white" : "border-white/10 bg-white/5"
          }`}
        >
          {/* Attach button */}
          <button
            title="Attach file (PDF, DOCX, CSV, image)"
            onClick={() => fileInputRef.current?.click()}
            className="flex-shrink-0 p-1.5 rounded-xl transition-colors hover:bg-purple-500/10 mb-0.5"
            style={{ color: attachedFiles.length > 0 ? "#a855f7" : "var(--fg-subtle)" }}
          >
            <Paperclip className="h-4 w-4" />
          </button>

          {/* Hidden file input */}
          <input
            ref={fileInputRef}
            type="file"
            accept={ACCEPTED}
            multiple
            className="hidden"
            onChange={(e) => { if (e.target.files) { addFiles(e.target.files); e.target.value = ""; } }}
          />

          {/* Text area */}
          <textarea
            ref={inputRef}
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder={
              attachedFiles.length > 0
                ? (attachedFiles.some(f => f.status === "uploading")
                    ? "Uploading…"
                    : "Ask about the attached document…")
                : t("chat_placeholder")
            }
            rows={1}
            disabled={isStreaming || isThinking}
            className="flex-1 resize-none bg-transparent text-sm focus:outline-none leading-relaxed max-h-28 disabled:opacity-50"
            style={{ minHeight: "24px", color: "var(--fg)", caretColor: "var(--fg)" }}
          />

          {/* Right controls */}
          <div className="flex items-center gap-1.5 mb-0.5 flex-shrink-0">
            <button
              title="Voice input"
              className="p-1.5 rounded-xl transition-colors"
              style={{ color: "var(--fg-subtle)" }}
            >
              <Mic className="h-4 w-4" />
            </button>

            <motion.button
              whileHover={{ scale: canSend ? 1.05 : 1 }}
              whileTap={{ scale: canSend ? 0.95 : 1 }}
              onClick={() => sendMessage()}
              disabled={!canSend}
              title="Send"
              className="flex h-8 w-8 items-center justify-center rounded-xl bg-gradient-to-br from-emerald-500 to-cyan-500 text-white disabled:opacity-40 disabled:cursor-not-allowed transition-opacity"
            >
              <Send className="h-3.5 w-3.5" />
            </motion.button>
          </div>
        </div>

        {/* Footer hint */}
        <p className="text-center text-[10px] mt-2" style={{ color: "var(--fg-subtle)" }}>
          Attach PDF · DOCX · CSV · TXT · Images &nbsp;·&nbsp; AI responses are informational, not financial advice
        </p>
      </div>
    </div>
  );
}
