import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { Sparkles, X, Send, Mic, MicOff, Maximize2, RefreshCw, Cloud, MapPin, Play, Volume2, VolumeX, Camera, ScanBarcode } from "lucide-react";
import { api } from "@/lib/api";
import { useCompany } from "@/context/CompanyContext";
import { useAuth } from "@/context/AuthContext";
import { useAiMode } from "@/context/AiModeContext";
import { useI18n } from "@/context/I18nContext";
import { LANG_BY_CODE } from "@/lib/languages";
import { toast } from "sonner";
import { Link, useLocation, useNavigate } from "react-router-dom";
import ReactMarkdown from "react-markdown";
import {
    isSpeechApiSupported,
    shouldFallbackToCloud,
    SPEECH_ERROR_MESSAGES,
    recordAudioBlob,
    cloudTranscribe,
} from "@/lib/voiceRecorder";
import { findGuide, detectNavIntent } from "@/lib/moduleGuide";
import { chooseVoiceForReply } from "@/lib/voicePicker";
import CameraCapture from "@/components/CameraCapture";
import AutoProductCreateDialog from "@/components/AutoProductCreateDialog";
import { useDraggable } from "@/hooks/useDraggable";

const DEFAULT_SUGGESTIONS = [
    "Aaj ka profit?",
    "Low stock items",
    "Top customers MTD",
    "GST liability this month",
];

/**
 * Floating AI Chat Widget — bottom-right pill.
 * Quick access to RBS REGAL AI Assistant from every page.
 * Voice input via Web Speech API.
 */
export function AiFloatingChat() {
    const { user } = useAuth();
    const { activeId } = useCompany();
    const { aiMode } = useAiMode();
    const { lang } = useI18n();
    const location = useLocation();
    const navigate = useNavigate();
    const [open, setOpen] = useState(false);
    const [messages, setMessages] = useState([]);
    const [input, setInput] = useState("");
    const [thinking, setThinking] = useState(false);
    const [recognizing, setRecognizing] = useState(false);
    const [transcribing, setTranscribing] = useState(false);
    const [usingCloud, setUsingCloud] = useState(false);
    const [ttsEnabled, setTtsEnabled] = useState(() => localStorage.getItem("rbs_ai_tts") === "1");
    const [cameraOpen, setCameraOpen] = useState(false);
    const [productDialog, setProductDialog] = useState(null);  // { vision, imageDataUrl } | null

    // Free-drag with persisted position (default = bottom:176px right:20px, matches `bottom-44 right-5`)
    const aiDrag = useDraggable({ key: "ai", defaultPosition: { right: 20, bottom: 176 } });

    useEffect(() => {
        localStorage.setItem("rbs_ai_tts", ttsEnabled ? "1" : "0");
        if (!ttsEnabled && "speechSynthesis" in window) {
            window.speechSynthesis.cancel();
        }
    }, [ttsEnabled]);
    const sessionId = useRef(`fab-${Date.now()}`);
    const listRef = useRef(null);
    const recogRef = useRef(null);
    const recorderRef = useRef(null);          // MediaRecorder controller

    // Resolve the current module guide from the route path
    const moduleGuide = useMemo(() => findGuide(location.pathname), [location.pathname]);
    const suggestions = moduleGuide?.prompts || DEFAULT_SUGGESTIONS;

    // Page-specific video tutorial — only shown if the user has the
    // `video_tutorials` flag enabled by Super Admin.
    const [tutorial, setTutorial] = useState(null);
    useEffect(() => {
        let alive = true;
        api.get("/module-tutorials/me", { params: { path: location.pathname } })
            .then((r) => { if (alive) setTutorial(r.data?.enabled && r.data?.video_url ? r.data : null); })
            .catch(() => { if (alive) setTutorial(null); });
        return () => { alive = false; };
    }, [location.pathname]);

    useEffect(() => {
        if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;
    }, [messages, thinking, open]);

    const send = useCallback(async (text) => {
        const q = (text || "").trim();
        if (!q || thinking) return;

        // === Navigation intent shortcut: "Naya GST bill banao" → /sales/new ===
        const intent = detectNavIntent(q);
        if (intent) {
            setMessages((m) => [...m, { role: "user", text: q }, { role: "assistant", text: intent.say, nav: intent.to }]);
            setInput("");
            // Slight delay so the user sees the assistant's confirmation message
            setTimeout(() => { navigate(intent.to); setOpen(false); }, 600);
            return;
        }

        // === Camera intent: "barcode scan", "photo se add", "scan karo" → open camera ===
        const camIntent = /\b(scan|barcode|qr|camera|कैमरा|बारकोड|photo se add|kya hai\??$|ye kya hai)\b/i.test(q);
        if (camIntent && (q.length < 40)) {
            setMessages((m) => [...m, { role: "user", text: q }, { role: "assistant", text: "📷 Camera khol raha hoon — barcode/QR ke liye ya AI-identify ke liye." }]);
            setInput("");
            setTimeout(() => setCameraOpen(true), 250);
            return;
        }

        setMessages((m) => [...m, { role: "user", text: q }]);
        setInput("");
        setThinking(true);
        try {
            // Prepend screen-context so the AI knows where the user is sitting
            const screenLine = moduleGuide
                ? `[Screen context: User abhi ${moduleGuide.title} page (${moduleGuide.path}) par hain — ${moduleGuide.description}]`
                : "";
            // Language instruction — auto-detect when user types in mixed/native script
            const langInfo = LANG_BY_CODE[lang] || LANG_BY_CODE.en;
            const langLine = lang === "en"
                ? "[Auto-detect the user's language from their message script. If they wrote in Hindi/Hinglish/Marathi/Gujarati/Tamil/Telugu/Bengali/Kannada/Malayalam/Punjabi/Odia/Urdu/Konkani, reply in that same language. Default to English otherwise. Brand names like RGE REGALGOA, GST, UPI, WhatsApp stay English. Numbers use Indian conventions.]"
                : `[Reply in ${langInfo.name} (${langInfo.native}) UNLESS the user explicitly wrote in a different language — in that case, mirror their language. Brand names like RGE REGALGOA, GST, UPI, WhatsApp stay English. Numbers use Indian conventions.]`;
            // Smart-prompt guidance — handles short/broken/mixed inputs naturally
            const smartLine = "[Smart interpretation: The user may type very short prompts (\"sale today?\"), broken grammar (\"item kya use\"), mixed-language (\"is item ka use kya hai?\"), or voice-style commands. Interpret intent generously and answer directly without asking for clarification unless absolutely necessary. If user asks 'ye kya hai' or 'is item ka use' about a specific item, treat it as an item knowledge query and reply with category + purpose + related items.]";
            const combinedPrefix = [screenLine, langLine, smartLine].filter(Boolean).join("\n");
            const { data } = await api.post("/ai/chat", {
                message: combinedPrefix ? `${combinedPrefix}\n\n${q}` : q,
                company_id: activeId,
                session_id: sessionId.current,
            });
            setMessages((m) => [...m, { role: "assistant", text: data.reply }]);
            // Auto-TTS — Female Indian voice, language detected from the reply's
            // script (NOT the UI lang toggle) so a Tamil reply is read in a Tamil
            // voice. See lib/voicePicker.js for ranking heuristics.
            if (ttsEnabled && "speechSynthesis" in window && data?.reply) {
                try {
                    window.speechSynthesis.cancel();
                    // Slightly longer cap (600) — Indian languages are word-dense.
                    const u = new SpeechSynthesisUtterance(data.reply.slice(0, 600));
                    // Pick female Indian voice (async — voices may not be loaded yet).
                    chooseVoiceForReply(data.reply, lang).then(({ voice, lang: vlang }) => {
                        if (voice) u.voice = voice;
                        u.lang = vlang || "en-IN";
                        u.rate = 0.95;       // comfortable Indian speaking speed
                        u.pitch = 1.05;      // slightly warmer / softer
                        u.volume = 1.0;
                        window.speechSynthesis.speak(u);
                    });
                } catch (_) { /* TTS optional */ }
            }
        } catch (e) {
            const msg = e.response?.data?.detail || "AI request failed";
            setMessages((m) => [...m, { role: "assistant", text: `⚠️ ${msg}`, error: true }]);
            toast.error(msg);
        } finally {
            setThinking(false);
        }
    }, [thinking, activeId, moduleGuide, navigate, lang, ttsEnabled]);

    // --------------- Cloud transcription fallback -----------------
    const recordAndTranscribe = useCallback(async () => {
        if (recorderRef.current) return;       // already recording
        try {
            const ctrl = await recordAudioBlob({ maxMs: 30000 });
            recorderRef.current = ctrl;
            setUsingCloud(true);
            setRecognizing(true);
            const blob = await ctrl.promise;
            recorderRef.current = null;
            setRecognizing(false);
            if (!blob) {                       // cancelled
                setUsingCloud(false);
                return;
            }
            setTranscribing(true);
            // Use the user's selected language for cloud STT (Whisper-compatible 2-letter code)
            const sttLang = (lang === "en") ? "en" : lang;
            const text = await cloudTranscribe(blob, { language: sttLang });
            setTranscribing(false);
            setUsingCloud(false);
            if (text && text.trim()) {
                setInput(text);
                setTimeout(() => send(text), 50);
            } else {
                toast.error("Couldn't hear anything — please try again.");
            }
        } catch (err) {
            recorderRef.current = null;
            setRecognizing(false);
            setTranscribing(false);
            setUsingCloud(false);
            console.warn("[AiFloatingChat] cloud transcribe failed:", err);
            toast.error(err?.response?.data?.detail || err?.message || "Voice transcription failed. Please type instead.");
        }
    }, [send, lang]);

    // --------------- Browser Web Speech API (preferred) -----------------
    const startVoice = () => {
        // Guard: already running (browser or cloud)
        if (recognizing || recogRef.current || recorderRef.current) {
            toast.info("Voice is already listening. Click again to stop.");
            return;
        }
        // HTTPS sanity check — both APIs need it
        if (typeof window !== "undefined" && !window.isSecureContext) {
            toast.error("Voice requires a secure HTTPS connection.");
            return;
        }
        // Fast path: cloud-only when browser doesn't support Web Speech
        if (!isSpeechApiSupported()) {
            recordAndTranscribe();
            return;
        }
        const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
        const r = new SR();
        // Map our i18n code to BCP-47 (Speech Recognition standard)
        const BCP47 = {
            en: "en-IN", hi: "hi-IN", gu: "gu-IN", mr: "mr-IN", pa: "pa-IN",
            bn: "bn-IN", ta: "ta-IN", te: "te-IN", kn: "kn-IN", ml: "ml-IN",
            or: "or-IN", ur: "ur-IN", kok: "kok-IN",
        };
        r.lang = BCP47[lang] || "en-IN";
        r.interimResults = true;
        r.continuous = false;
        r.onstart = () => { setRecognizing(true); setUsingCloud(false); };
        r.onerror = (e) => {
            setRecognizing(false);
            recogRef.current = null;
            const code = e.error || "unknown";
            console.warn("[AiFloatingChat] SpeechRecognition error:", code, e);
            // If the browser engine itself failed (network/aborted), silently
            // switch to cloud Whisper — user shouldn't have to retry manually.
            if (shouldFallbackToCloud(code)) {
                toast.info("Browser voice unavailable — using cloud transcription…", { duration: 1800 });
                recordAndTranscribe();
                return;
            }
            toast.error(SPEECH_ERROR_MESSAGES[code] || `Voice error (${code}). Please try again.`);
        };
        r.onend = () => { setRecognizing(false); recogRef.current = null; };
        r.onresult = (ev) => {
            const txt = Array.from(ev.results).map((res) => res[0].transcript).join("");
            setInput(txt);
            if (ev.results[0].isFinal) setTimeout(() => send(txt), 100);
        };
        try {
            r.start();
            recogRef.current = r;
        } catch (err) {
            console.error("[AiFloatingChat] r.start() failed:", err);
            setRecognizing(false);
            recogRef.current = null;
            // start() can throw "already started" or InvalidStateError — fall back to cloud
            recordAndTranscribe();
        }
    };
    const stopVoice = () => {
        // Stop whichever path is active
        try { recogRef.current?.stop(); } catch (e) { console.debug("[AiFloatingChat] stopVoice (browser) failed:", e?.message); }
        recogRef.current = null;
        try { recorderRef.current?.stop(); } catch (e) { console.debug("[AiFloatingChat] stopVoice (cloud) failed:", e?.message); }
        if (!recorderRef.current) setRecognizing(false);
    };

    // ----------- Camera result handler -----------
    const handleCameraResult = useCallback(async (result) => {
        if (!result) return;
        // === Existing flows ===
        if (result.kind === "item_match") {
            const it = result.item;
            setMessages((m) => [
                ...m,
                { role: "user", text: `📷 [Scanned: ${result.code}]` },
                { role: "assistant", text: `✅ **${it.name}** mil gaya!\n\n- Code: \`${it.code || result.code}\`\n- Stock: ${it.current_stock ?? "?"} ${it.base_unit || ""}\n- Last sale price: ₹${it.last_sale_price || it.sale_price || "?"}\n\nKya aap is item ko **Sale** ya **Purchase** mein add karna chahenge? Niche "+ Sale" / "+ Purchase" button daba kar continue karein.` },
            ]);
            // Stash for one-click handoff via the next chat action
            try {
                sessionStorage.setItem("rbs_pending_scan_line_v1", JSON.stringify({
                    item_id: it.id, name: it.name, hsn: it.hsn || "",
                    unit: it.base_unit || it.unit || "PCS",
                    rate: it.sale_price || it.last_sale_price || 0,
                    gst_rate: it.gst_rate ?? 18,
                    qty: 1, target_mode: "sale",
                }));
            } catch { /* ignore */ }
            // Auto-navigate to /sales/new (most common scan-to-sell flow)
            setTimeout(() => { navigate("/sales/new"); setOpen(false); }, 900);
            return;
        }
        if (result.kind === "barcode_unmatched" || result.kind === "barcode") {
            setMessages((m) => [
                ...m,
                { role: "user", text: `📷 [Scanned: ${result.code}]` },
                { role: "assistant", text: `⚠ Code \`${result.code}\` catalog mein nahi mila. Camera ko **AI Identify** mode mein switch karein — main pehchaan kar draft item banwa dunga.` },
            ]);
            return;
        }
        if (result.kind === "ai_identify") {
            const p = result.payload || {};
            const matched = p.matched_item ? `\n\n✓ Existing match: **${p.matched_item.name}** (stock ${p.matched_item.current_stock ?? "?"} ${p.matched_item.base_unit || ""})` : "";
            const related = (p.related && p.related.length) ? `\n- Related: ${p.related.join(", ")}` : "";
            setMessages((m) => [
                ...m,
                { role: "user", text: `📷 [AI Identify]` },
                { role: "assistant", text: `🔍 **${p.name || "Unknown item"}**\n\n- Category: ${p.category || "?"}\n- Usage: ${p.purpose || "?"}\n- Unit: ${p.unit || "PCS"}${related}${matched}\n\nConfidence: ${Math.round(((p.confidence || 0) * 100))}%` },
            ]);
            return;
        }

        // === New action flows (camera CTAs → auto-accounting) ===
        if (result.kind === "create_draft") {
            // Open the Auto Product Create dialog with the AI's vision payload
            // pre-filled into editable fields, including the captured photo.
            setProductDialog({ vision: result.payload, imageDataUrl: result.image });
            return;
        }
        if (result.kind === "add_to_sale" || result.kind === "add_to_purchase") {
            const p = result.payload || {};
            const targetMode = result.kind === "add_to_purchase" ? "purchase" : "sale";
            const targetUrl = targetMode === "purchase" ? "/purchases/new" : "/sales/new";
            try {
                sessionStorage.setItem("rbs_pending_scan_line_v1", JSON.stringify({
                    item_id: p.matched_item?.id || null,
                    name: p.matched_item?.name || p.name || "",
                    hsn: p.matched_item?.hsn || p.hsn || "",
                    unit: p.matched_item?.base_unit || p.unit || "PCS",
                    rate: p.matched_item?.sale_price || 0,
                    gst_rate: p.matched_item?.gst_rate ?? 18,
                    brand: p.brand || "",
                    qty: 1,
                    target_mode: targetMode,
                }));
            } catch (e) {
                toast.error("Could not stash scan: " + (e?.message || ""));
                return;
            }
            toast.success(`Adding to ${targetMode === "purchase" ? "Purchase" : "Sale"}…`);
            setMessages((m) => [...m, { role: "assistant", text: `➡ ${result.kind === "add_to_purchase" ? "Purchase" : "Sale"} mein add kar raha hoon — ${p.name || p.matched_item?.name || "item"}.` }]);
            setTimeout(() => { navigate(targetUrl); setOpen(false); }, 600);
            return;
        }
    }, [activeId, navigate]);

    // Don't render if user not logged in OR AI mode is disabled
    if (!user || !aiMode) return null;

    return (
        <>
            {/* Trigger button — draggable, default bottom-44 right-5, above WhatsApp FAB */}
            {!open && (
                <button
                    ref={aiDrag.ref}
                    type="button"
                    onClick={() => setOpen(true)}
                    draggable={false}
                    aria-label="Open AI Assistant (drag to reposition)"
                    data-testid="ai-fab-open"
                    className="group z-50"
                    style={aiDrag.style}
                    {...aiDrag.bind}
                >
                    <span className="absolute inset-0 rounded-full bg-amber-400/40 animate-ping pointer-events-none" aria-hidden />
                    <span className="relative flex items-center justify-center h-14 w-14 rounded-full bg-gradient-to-br from-amber-400 via-yellow-500 to-amber-600 text-white shadow-xl shadow-amber-900/30 ring-2 ring-white/40 transition-transform hover:scale-110 active:scale-95">
                        <Sparkles className="h-6 w-6" strokeWidth={2.2} />
                    </span>
                    <span className="absolute right-16 top-1/2 -translate-y-1/2 whitespace-nowrap rounded-md bg-foreground/90 text-background text-xs px-2 py-1 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
                        AI Assistant — Voice + Chat
                    </span>
                </button>
            )}

            {/* Chat panel */}
            {open && (
                <div
                    role="dialog"
                    aria-label="RGE REGALGOA AI Assistant"
                    data-testid="ai-fab-panel"
                    className="fixed bottom-20 right-5 z-50 w-[92vw] sm:w-[400px] h-[560px] max-h-[80vh] rounded-2xl border border-border bg-card shadow-2xl shadow-black/30 flex flex-col overflow-hidden animate-in fade-in slide-in-from-bottom-4 duration-200"
                >
                    {/* Header */}
                    <div className="flex items-center justify-between px-4 py-2.5 bg-gradient-to-r from-blue-800 to-blue-950 text-white">
                        <div className="flex items-center gap-2 min-w-0">
                            <div className="h-8 w-8 rounded-full bg-gradient-to-br from-amber-300 to-amber-600 flex items-center justify-center flex-shrink-0">
                                <Sparkles className="h-4 w-4 text-blue-950" strokeWidth={2.4} />
                            </div>
                            <div className="min-w-0">
                                <div className="text-sm font-semibold leading-tight">RGE REGALGOA AI</div>
                                <div className="text-[10px] uppercase tracking-wide text-blue-100/70">Business Assistant</div>
                            </div>
                        </div>
                        <div className="flex items-center gap-1">
                            <Link
                                to="/ai"
                                onClick={() => setOpen(false)}
                                aria-label="Open full assistant"
                                data-testid="ai-fab-expand"
                                className="p-1.5 rounded hover:bg-white/15 text-white/90 hover:text-white transition"
                            >
                                <Maximize2 className="h-3.5 w-3.5" />
                            </Link>
                            <button
                                type="button"
                                onClick={() => setOpen(false)}
                                aria-label="Close"
                                data-testid="ai-fab-close"
                                className="p-1.5 rounded hover:bg-white/15 text-white/90 hover:text-white transition"
                            >
                                <X className="h-4 w-4" />
                            </button>
                        </div>
                    </div>

                    {/* Body */}
                    <div ref={listRef} className="flex-1 overflow-y-auto p-3 space-y-3 bg-muted/10" data-testid="ai-fab-messages">
                        {messages.length === 0 ? (
                            <div className="text-center py-3">
                                {/* Screen-aware banner — tells the user where they are */}
                                {moduleGuide ? (
                                    <div className="rounded-lg border border-blue-500/30 bg-blue-500/5 p-2.5 text-left mb-3" data-testid="ai-fab-module-banner">
                                        <div className="flex items-center gap-2">
                                            <MapPin className="h-3.5 w-3.5 text-blue-600 shrink-0" />
                                            <div className="text-[10px] uppercase tracking-wider text-blue-700 dark:text-blue-400 font-semibold">You are here</div>
                                        </div>
                                        <div className="mt-1 text-sm font-bold">{moduleGuide.emoji} {moduleGuide.title}</div>
                                        <p className="text-[11px] text-muted-foreground mt-0.5 leading-snug">{moduleGuide.description}</p>
                                        {/* Video tutorial CTA — only when Super Admin has set a video and
                                            user has `video_tutorials` flag enabled */}
                                        {tutorial?.video_url && (
                                            <a
                                                href={tutorial.video_url}
                                                target="_blank"
                                                rel="noopener noreferrer"
                                                className="mt-2 inline-flex items-center gap-1.5 text-[11px] font-semibold rounded-full bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/30 text-rose-600 px-2.5 py-1 transition"
                                                data-testid="ai-fab-video-tutorial"
                                            >
                                                <Play className="h-3 w-3 fill-current" />
                                                ▶ Watch {Math.round((tutorial.duration_seconds || 120) / 60)}-min tutorial
                                            </a>
                                        )}
                                    </div>
                                ) : (
                                    <>
                                        <Sparkles className="h-9 w-9 text-amber-500/60 mx-auto mb-2" />
                                        <div className="text-xs font-medium">Namaste {user?.name?.split(" ")[0] || "Boss"}! 👋</div>
                                        <p className="text-[11px] text-muted-foreground mt-1 px-2">
                                            Hindi ya English mein puchhiye — sales, stock, GST, ya business tips.
                                        </p>
                                    </>
                                )}
                                <div className="text-[10px] uppercase tracking-wider text-muted-foreground mt-1 mb-1.5">Suggested questions</div>
                                <div className="flex flex-wrap gap-1.5 justify-center px-1">
                                    {suggestions.map((s) => (
                                        <button
                                            key={s}
                                            type="button"
                                            onClick={() => send(s)}
                                            className="text-[11px] px-2.5 py-1 rounded-full border bg-card hover:bg-amber-50 hover:border-amber-400 dark:hover:bg-amber-950/30 transition-colors"
                                            data-testid={`ai-fab-suggest-${s.slice(0, 8).replace(/\s+/g, "_")}`}
                                        >
                                            {s}
                                        </button>
                                    ))}
                                </div>
                                <div className="mt-3 pt-2 border-t border-dashed border-border/50 text-[10px] text-muted-foreground px-2">
                                    💡 Try: <em>&ldquo;Naya GST bill banao&rdquo;</em>, <em>&ldquo;POS kholo&rdquo;</em>, <em>&ldquo;Backup lo&rdquo;</em>
                                </div>
                            </div>
                        ) : (
                            messages.map((m, i) => <Bubble key={i} {...m} />)
                        )}
                        {thinking && <Bubble role="assistant" text="…" thinking />}
                    </div>

                    {/* Input */}
                    <div className="border-t bg-card p-2.5 flex items-center gap-1.5">
                        <button
                            type="button"
                            onClick={() => setTtsEnabled((v) => !v)}
                            aria-label={ttsEnabled ? "Mute AI voice reply" : "Speak AI replies"}
                            data-testid="ai-fab-tts-toggle"
                            title={ttsEnabled ? "TTS ON — AI replies will be spoken in your language" : "TTS OFF — AI replies are text only"}
                            className={`h-9 w-9 rounded-full flex items-center justify-center transition flex-shrink-0 border ${ttsEnabled ? "bg-blue-600 text-white" : "bg-card hover:bg-muted"}`}
                        >
                            {ttsEnabled ? <Volume2 className="h-4 w-4" /> : <VolumeX className="h-4 w-4" />}
                        </button>
                        <button
                            type="button"
                            onClick={() => setCameraOpen(true)}
                            aria-label="Open Camera — barcode scan or AI identify"
                            data-testid="ai-fab-camera"
                            title="Camera: Barcode/QR scan + AI item identify"
                            className="h-9 w-9 rounded-full flex items-center justify-center transition flex-shrink-0 border bg-card hover:bg-amber-50 hover:border-amber-400"
                        >
                            <Camera className="h-4 w-4" />
                        </button>
                        <button
                            type="button"
                            onClick={recognizing || transcribing ? stopVoice : startVoice}
                            disabled={transcribing}
                            aria-label={recognizing ? "Stop voice" : "Start voice"}
                            data-testid="ai-fab-voice"
                            title={usingCloud ? "Cloud transcription (Whisper)" : "Browser voice"}
                            className={`h-9 w-9 rounded-full flex items-center justify-center transition flex-shrink-0 ${recognizing ? (usingCloud ? "bg-sky-500 text-white animate-pulse" : "bg-rose-500 text-white animate-pulse") : "border bg-card hover:bg-muted"}`}
                        >
                            {transcribing ? <RefreshCw className="h-4 w-4 animate-spin" /> : recognizing ? (usingCloud ? <Cloud className="h-4 w-4" /> : <MicOff className="h-4 w-4" />) : <Mic className="h-4 w-4" />}
                        </button>
                        <input
                            type="text"
                            value={input}
                            onChange={(e) => setInput(e.target.value)}
                            onKeyDown={(e) => { if (e.key === "Enter") send(input); }}
                            placeholder={transcribing ? "☁ Transcribing…" : recognizing ? (usingCloud ? "☁ Listening (cloud)…" : "🎤 Listening…") : "Ask anything…"}
                            disabled={recognizing || thinking || transcribing}
                            data-testid="ai-fab-input"
                            className="flex-1 min-w-0 h-9 px-3 text-sm rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-blue-600/40"
                        />
                        <button
                            type="button"
                            onClick={() => send(input)}
                            disabled={!input.trim() || thinking}
                            aria-label="Send"
                            data-testid="ai-fab-send"
                            className="h-9 w-9 rounded-full flex items-center justify-center bg-blue-700 hover:bg-blue-800 text-white disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0 transition"
                        >
                            {thinking ? <RefreshCw className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
                        </button>
                    </div>
                </div>
            )}

            {/* Camera Capture — barcode/QR + AI Vision identify */}
            {cameraOpen && (
                <CameraCapture
                    onResult={handleCameraResult}
                    onClose={() => setCameraOpen(false)}
                    companyId={activeId}
                />
            )}

            {/* Auto Product Create — confirm popup with editable AI-detected fields */}
            <AutoProductCreateDialog
                open={!!productDialog}
                vision={productDialog?.vision}
                imageDataUrl={productDialog?.imageDataUrl}
                companyId={activeId}
                onClose={() => setProductDialog(null)}
                onSaved={(created) => {
                    setMessages((m) => [...m, { role: "assistant", text: `✅ **${created.name}** save ho gaya! ₹${created.mrp || created.sale_price || 0} · stock ${created.current_stock || 0} ${created.base_unit || "PCS"}. /items page par dikhega.` }]);
                }}
            />
        </>
    );
}

function Bubble({ role, text, thinking, error }) {
    const isUser = role === "user";
    return (
        <div className={`flex gap-1.5 ${isUser ? "justify-end" : "justify-start"}`}>
            {!isUser && (
                <div className="h-6 w-6 rounded-full bg-gradient-to-br from-amber-300 to-amber-600 flex items-center justify-center flex-shrink-0 mt-0.5">
                    <Sparkles className="h-3 w-3 text-blue-950" />
                </div>
            )}
            <div className={`max-w-[82%] rounded-2xl px-3 py-1.5 text-sm ${isUser ? "bg-blue-700 text-white" : error ? "bg-rose-50 text-rose-900 dark:bg-rose-950/30 dark:text-rose-200" : "bg-card border border-border"}`}>
                {thinking ? (
                    <div className="flex gap-1 py-1 px-0.5">
                        <span className="h-1.5 w-1.5 bg-muted-foreground rounded-full animate-bounce" />
                        <span className="h-1.5 w-1.5 bg-muted-foreground rounded-full animate-bounce" style={{ animationDelay: "0.15s" }} />
                        <span className="h-1.5 w-1.5 bg-muted-foreground rounded-full animate-bounce" style={{ animationDelay: "0.3s" }} />
                    </div>
                ) : isUser ? (
                    <p className="whitespace-pre-wrap text-[13px]">{text}</p>
                ) : (
                    <div className="prose prose-sm dark:prose-invert max-w-none text-[13px] [&>p]:my-1 [&>ul]:my-1">
                        <ReactMarkdown>{text}</ReactMarkdown>
                    </div>
                )}
            </div>
        </div>
    );
}

export default AiFloatingChat;
