import { useRef, useState } from 'react'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import { motion } from 'framer-motion'
import { ChevronDown, ChevronUp, BookOpen, Hash, LoaderCircle, Volume2, VolumeX } from 'lucide-react'
import { Stethoscope, User } from 'lucide-react'
import clsx from 'clsx'
import toast from 'react-hot-toast'

import { audioApi, getApiErrorMessage } from '../../api/client'

function TypingDots() {
  return (
    <div className="flex items-center gap-1 py-1">
      <span className="typing-dot" />
      <span className="typing-dot" />
      <span className="typing-dot" />
    </div>
  )
}

function SourceCard({ source, index }) {
  const [open, setOpen] = useState(false)
  return (
    <div className="border border-white/8 rounded-lg overflow-hidden text-xs">
      <button
        onClick={() => setOpen(o => !o)}
        className="w-full flex items-center gap-2 px-3 py-2 bg-surface-3 hover:bg-surface-4 transition-colors text-left"
      >
        <span className="w-5 h-5 rounded-full bg-accent/20 text-accent flex items-center justify-center font-bold text-[10px] shrink-0">{index}</span>
        <div className="flex-1 min-w-0">
          <p className="text-white/80 font-medium truncate">{source.title}</p>
          <p className="text-gray-500 truncate">
            {source.filename}
            {source.page_number ? ` | page ${source.page_number}` : ''}
            {source.retrieval_method ? ` | ${source.retrieval_method}` : ''}
          </p>
        </div>
        <span className="text-gray-500 shrink-0 font-mono">{(source.score * 100).toFixed(0)}%</span>
        {open ? <ChevronUp size={12} className="text-gray-500 shrink-0" /> : <ChevronDown size={12} className="text-gray-500 shrink-0" />}
      </button>
      {open && (
        <div className="px-3 py-2 bg-surface-2 border-t border-white/5 text-gray-400 leading-relaxed text-[11px] max-h-40 overflow-y-auto">
          <div className="flex items-center gap-3 text-[10px] text-gray-500 mb-2">
            <span className="flex items-center gap-1"><Hash size={10} /> chunk {source.chunk_index}</span>
            {source.page_number ? <span>page {source.page_number}</span> : null}
            <span className="font-mono">{source.doc_id.slice(0, 8)}</span>
          </div>
          {source.text}
        </div>
      )}
    </div>
  )
}

export default function MessageBubble({ message, isStreaming = false }) {
  const [showSources, setShowSources] = useState(false)
  const [isSpeaking, setIsSpeaking] = useState(false)
  const isUser = message.role === 'user'
  const sources = message.sources || []
  const audioRef = useRef(null)

  const handleSpeak = async () => {
    if (!message.content?.trim()) return

    if (audioRef.current && !audioRef.current.paused) {
      audioRef.current.pause()
      audioRef.current.currentTime = 0
      setIsSpeaking(false)
      return
    }

    setIsSpeaking(true)
    try {
      const blob = await audioApi.speak({ text: message.content })
      const url = URL.createObjectURL(blob)
      const audio = new Audio(url)
      audioRef.current = audio
      audio.onended = () => {
        URL.revokeObjectURL(url)
        setIsSpeaking(false)
      }
      audio.onerror = () => {
        URL.revokeObjectURL(url)
        setIsSpeaking(false)
      }
      await audio.play()
    } catch (err) {
      setIsSpeaking(false)
      toast.error(getApiErrorMessage(err, 'Failed to generate speech'))
    }
  }

  return (
    <motion.div
      initial={{ opacity: 0, y: 10 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.2 }}
      className={clsx('flex gap-3 group', isUser && 'flex-row-reverse')}
    >
      <div className={clsx(
        'w-8 h-8 rounded-xl flex items-center justify-center shrink-0 mt-0.5',
        isUser ? 'bg-accent/20 border border-accent/30' : 'bg-med-teal/10 border border-med-teal/20'
      )}>
        {isUser
          ? <User size={14} className="text-accent" />
          : <Stethoscope size={14} className="text-med-teal" />
        }
      </div>

      <div className={clsx('flex-1 min-w-0 max-w-2xl', isUser && 'flex flex-col items-end')}>
        {isUser ? (
          <div className="bg-accent/10 border border-accent/20 rounded-2xl rounded-tr-sm px-4 py-3 text-sm text-white leading-relaxed">
            {message.content}
          </div>
        ) : (
          <div className="space-y-3">
            <div className="bg-surface-2 border border-white/5 rounded-2xl rounded-tl-sm px-4 py-3">
              {isStreaming ? (
                <TypingDots />
              ) : (
                <div className="space-y-3">
                  <div className="prose-dark text-sm leading-relaxed">
                    <ReactMarkdown remarkPlugins={[remarkGfm]}>
                      {message.content}
                    </ReactMarkdown>
                  </div>
                  <div className="flex items-center justify-end">
                    <button
                      onClick={handleSpeak}
                      className="flex items-center gap-1.5 text-xs text-gray-400 hover:text-white transition-colors"
                      title={isSpeaking ? 'Stop audio' : 'Play answer audio'}
                    >
                      {isSpeaking
                        ? <LoaderCircle size={12} className="animate-spin" />
                        : audioRef.current && !audioRef.current.paused
                          ? <VolumeX size={12} />
                          : <Volume2 size={12} />
                      }
                      {isSpeaking ? 'Speaking...' : 'Speak'}
                    </button>
                  </div>
                </div>
              )}
            </div>

            {!isStreaming && sources.length > 0 && (
              <div className="space-y-2">
                <button
                  onClick={() => setShowSources(s => !s)}
                  className="flex items-center gap-1.5 text-xs text-gray-500 hover:text-gray-300 transition-colors"
                >
                  <BookOpen size={11} />
                  {sources.length} source{sources.length !== 1 ? 's' : ''}
                  {showSources ? <ChevronUp size={11} /> : <ChevronDown size={11} />}
                </button>

                {showSources && (
                  <motion.div
                    initial={{ opacity: 0, height: 0 }}
                    animate={{ opacity: 1, height: 'auto' }}
                    exit={{ opacity: 0, height: 0 }}
                    className="space-y-1.5"
                  >
                    {sources.map((s, i) => (
                      <SourceCard key={i} source={s} index={i + 1} />
                    ))}
                  </motion.div>
                )}
              </div>
            )}
          </div>
        )}
      </div>
    </motion.div>
  )
}
