import { useState, useRef, useCallback } from 'react'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import { Volume2, Pause, Loader2, VolumeX } from 'lucide-react'
import { toast } from 'sonner'

type TTSState = 'idle' | 'loading' | 'playing' | 'paused'

interface TextToSpeechButtonProps {
    /** Pre-generated audio URL (for summaries) */
    audioUrl?: string
    /** Text to synthesize on-demand (for chat messages) */
    text?: string
    /** Button size variant */
    size?: 'sm' | 'default' | 'lg' | 'icon'
    /** Button variant */
    variant?: 'default' | 'outline' | 'ghost' | 'secondary'
    /** Additional CSS classes */
    className?: string
    /** Whether the button is disabled */
    disabled?: boolean
}

export function TextToSpeechButton({
    audioUrl,
    text,
    size = 'icon',
    variant = 'outline',
    className,
    disabled = false,
}: TextToSpeechButtonProps) {
    const [state, setState] = useState<TTSState>('idle')
    const audioRef = useRef<HTMLAudioElement | null>(null)
    const blobUrlRef = useRef<string | null>(null)

    const cleanup = useCallback(() => {
        if (audioRef.current) {
            audioRef.current.pause()
            audioRef.current.src = ''
            audioRef.current = null
        }
        if (blobUrlRef.current) {
            URL.revokeObjectURL(blobUrlRef.current)
            blobUrlRef.current = null
        }
    }, [])

    const handleEnded = useCallback(() => {
        setState('idle')
        cleanup()
    }, [cleanup])

    const handleError = useCallback(() => {
        setState('idle')
        cleanup()
        toast.error('Failed to play audio')
    }, [cleanup])

    const playPreGeneratedAudio = useCallback(async () => {
        if (!audioUrl) return

        setState('loading')

        try {
            const audio = new Audio(audioUrl)
            audioRef.current = audio

            audio.addEventListener('ended', handleEnded)
            audio.addEventListener('error', handleError)
            audio.addEventListener('canplaythrough', () => {
                audio.play()
                setState('playing')
            })

            audio.load()
        } catch {
            handleError()
        }
    }, [audioUrl, handleEnded, handleError])

    const synthesizeAndPlay = useCallback(async () => {
        if (!text) return

        setState('loading')

        try {
            const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')

            const response = await fetch('/api/tts/synthesize', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': csrfToken || '',
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'audio/mpeg',
                },
                body: JSON.stringify({ text }),
            })

            if (!response.ok) {
                throw new Error('Failed to synthesize audio')
            }

            const blob = await response.blob()
            const url = URL.createObjectURL(blob)
            blobUrlRef.current = url

            const audio = new Audio(url)
            audioRef.current = audio

            audio.addEventListener('ended', handleEnded)
            audio.addEventListener('error', handleError)

            await audio.play()
            setState('playing')
        } catch {
            handleError()
        }
    }, [text, handleEnded, handleError])

    const handleClick = useCallback(() => {
        switch (state) {
            case 'idle':
                if (audioUrl) {
                    playPreGeneratedAudio()
                } else if (text) {
                    synthesizeAndPlay()
                }
                break

            case 'playing':
                if (audioRef.current) {
                    audioRef.current.pause()
                    setState('paused')
                }
                break

            case 'paused':
                if (audioRef.current) {
                    audioRef.current.play()
                    setState('playing')
                }
                break

            case 'loading':
                // Do nothing while loading
                break
        }
    }, [state, audioUrl, text, playPreGeneratedAudio, synthesizeAndPlay])

    const handleStop = useCallback(() => {
        cleanup()
        setState('idle')
    }, [cleanup])

    // Determine if the button should be shown
    if (!audioUrl && !text) {
        return null
    }

    const getIcon = () => {
        switch (state) {
            case 'loading':
                return <Loader2 className="h-4 w-4 animate-spin" />
            case 'playing':
                return <Pause className="h-4 w-4" />
            case 'paused':
                return <Volume2 className="h-4 w-4" />
            default:
                return <Volume2 className="h-4 w-4" />
        }
    }

    const getLabel = () => {
        switch (state) {
            case 'loading':
                return 'Loading...'
            case 'playing':
                return 'Pause'
            case 'paused':
                return 'Resume'
            default:
                return 'Listen'
        }
    }

    const isIconOnly = size === 'icon' || size === 'sm'

    return (
        <div className={cn('inline-flex items-center gap-1', className)}>
            <Button
                type="button"
                variant={variant}
                size={size}
                onClick={handleClick}
                disabled={disabled || state === 'loading'}
                className={cn(
                    state === 'playing' && 'bg-primary/10'
                )}
                title={getLabel()}
            >
                {getIcon()}
                {!isIconOnly && <span className="ml-1">{getLabel()}</span>}
            </Button>

            {(state === 'playing' || state === 'paused') && (
                <Button
                    type="button"
                    variant="ghost"
                    size="icon"
                    onClick={handleStop}
                    className="h-8 w-8"
                    title="Stop"
                >
                    <VolumeX className="h-4 w-4" />
                </Button>
            )}
        </div>
    )
}
