import React, {
    forwardRef,
    useEffect,
    useImperativeHandle,
    useRef,
    useState,
} from 'react';

import { Lang } from '@/lang/Lang';

import AudioPlayer
    from './CollectionFields/components/ItemData/FileData/components/AudioPlayer';
import { Button } from './ui/button';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from './ui/dialog';

type OpenParams = {
    onSelect: (file: File) => void
}

type AudioRecordDialogRef = {
    open: (options: OpenParams) => void
    close: () => void
}

export const audioRecordDialogRef = React.createRef<AudioRecordDialogRef>();


const AudioRecordDialog = forwardRef<AudioRecordDialogRef, {}>((_, ref) => {

    const [isOpen, setIsOpen] = useState(false);
    const paramsRef = useRef<OpenParams | null>(null);

    const [status, setStatus] = useState<
        'idle' | 'recording' | 'recorded' | 'unsupported' | 'error'
    >('idle');
    const [errorMessage, setErrorMessage] = useState<string | null>(null);
    const [audioUrl, setAudioUrl] = useState<string | null>(null);
    const [recordedBlob, setRecordedBlob] = useState<Blob | null>(null);

    const streamRef = useRef<MediaStream | null>(null);
    const recorderRef = useRef<MediaRecorder | null>(null);
    const chunksRef = useRef<BlobPart[]>([]);

    const cleanupMedia = () => {
        try {
            if (recorderRef.current && recorderRef.current.state !== 'inactive') {
                recorderRef.current.stop();
            }
        } catch {
            // ignore
        }
        recorderRef.current = null;
        chunksRef.current = [];

        streamRef.current?.getTracks().forEach((t) => t.stop());
        streamRef.current = null;
    };

    const cleanupRecordingData = () => {
        if (audioUrl) {
            URL.revokeObjectURL(audioUrl);
        }
        setAudioUrl(null);
        setRecordedBlob(null);
    };

    const setInitialStatus = () => {
        const supported =
            typeof window !== 'undefined' &&
            'MediaRecorder' in window &&
            !!navigator?.mediaDevices?.getUserMedia;
        setStatus(supported ? 'idle' : 'unsupported');
    };

    const reset = () => {
        cleanupMedia();
        cleanupRecordingData();
        setErrorMessage(null);
        setInitialStatus();
    };

    const pickMimeType = (): string | undefined => {
        if (typeof window === 'undefined') return undefined;
        if (!('MediaRecorder' in window)) return undefined;

        // Prefer Opus where possible
        const candidates = [
            'audio/webm;codecs=opus',
            'audio/webm',
            'audio/ogg;codecs=opus',
            'audio/ogg',
            'audio/mp4',
        ];

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const MR: any = (window as any).MediaRecorder;
        if (typeof MR?.isTypeSupported !== 'function') return undefined;
        return candidates.find((t) => MR.isTypeSupported(t));
    };

    const startRecording = async () => {
        setErrorMessage(null);
        cleanupRecordingData();

        const supported =
            typeof window !== 'undefined' &&
            'MediaRecorder' in window &&
            !!navigator?.mediaDevices?.getUserMedia;
        if (!supported) {
            setStatus('unsupported');
            setErrorMessage('Запись аудио не поддерживается в этом браузере.');
            return;
        }

        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            streamRef.current = stream;

            const mimeType = pickMimeType();
            const recorder = mimeType
                ? new MediaRecorder(stream, { mimeType })
                : new MediaRecorder(stream);
            recorderRef.current = recorder;
            chunksRef.current = [];

            recorder.ondataavailable = (e: BlobEvent) => {
                if (e.data && e.data.size > 0) {
                    chunksRef.current.push(e.data);
                }
            };

            recorder.onerror = () => {
                cleanupMedia();
                setStatus('error');
                setErrorMessage('Ошибка записи. Попробуйте ещё раз.');
            };

            recorder.onstop = () => {
                const blob = new Blob(chunksRef.current, {
                    type: recorder.mimeType || 'audio/webm',
                });
                chunksRef.current = [];
                cleanupMedia();

                const url = URL.createObjectURL(blob);
                setRecordedBlob(blob);
                setAudioUrl(url);
                setStatus('recorded');
            };

            recorder.start();
            setStatus('recording');
        } catch {
            cleanupMedia();
            setStatus('error');
            setErrorMessage('Не удалось получить доступ к микрофону.');
        }
    };

    const stopRecording = () => {
        try {
            if (recorderRef.current && recorderRef.current.state !== 'inactive') {
                recorderRef.current.stop();
            }
        } catch {
            cleanupMedia();
            setStatus('error');
            setErrorMessage('Не удалось остановить запись.');
        }
    };

    const applyRecording = () => {
        if (!recordedBlob || !paramsRef.current) return;

        const mime = recordedBlob.type || 'audio/webm';
        const ext =
            mime.includes('ogg') ? 'ogg' : mime.includes('mp4') ? 'm4a' : 'webm';

        const file = new File([recordedBlob], `recording-${Date.now()}.${ext}`, {
            type: mime,
        });

        paramsRef.current.onSelect(file);
        setIsOpen(false);
    };

    useImperativeHandle(ref, () => ({
        open: (options: OpenParams) => {
            paramsRef.current = options;
            reset();
            setIsOpen(true);
        },
        close: () => {
            setIsOpen(false);
        }
    }));

    useEffect(() => {
        if (!isOpen) {
            cleanupMedia();
            cleanupRecordingData();
            setErrorMessage(null);
            setInitialStatus();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isOpen]);

    if (!isOpen) return null;
    return (
        <Dialog open={isOpen} onOpenChange={setIsOpen}>

            <DialogContent>
                <DialogHeader>
                    <DialogTitle>{Lang.key('record_audio')}</DialogTitle>
                    <DialogDescription>
                        {Lang.key('start_recording_stop_listen_apply')}
                    </DialogDescription>
                </DialogHeader>

                <div className="space-y-3">
                    {errorMessage && (
                        <div className="text-sm text-destructive">{errorMessage}</div>
                    )}

                    {status === 'idle' && (
                        <Button type="button" onClick={startRecording}>
                            {Lang.key('start_recording')}
                        </Button>
                    )}

                    {status === 'unsupported' && (
                        <div className="text-sm text-muted-foreground">
                            {Lang.key('recording_audio_not_supported_in_this_browser')}
                        </div>
                    )}

                    {status === 'recording' && (
                        <div className="flex items-center gap-2">
                            <Button
                                type="button"
                                variant="destructive"
                                onClick={stopRecording}
                            >
                                {Lang.key('stop_recording')}
                            </Button>
                            <span className="text-sm text-muted-foreground">
                                {Lang.key('recording_in_progress')}
                            </span>
                        </div>
                    )}

                    {status === 'recorded' && audioUrl && (
                        <div className="space-y-3">

                            <AudioPlayer src={audioUrl} />
                            <div className="flex flex-wrap gap-2">
                                <Button type="button" variant="outline" onClick={startRecording}>
                                    {Lang.key('rerecord')}
                                </Button>
                                <Button type="button" onClick={applyRecording}>
                                    {Lang.key('save')}
                                </Button>
                            </div>
                        </div>
                    )}
                </div>

                <DialogFooter>
                    <Button type="button" variant="ghost" onClick={() => setIsOpen(false)}>
                        {Lang.key('close')}
                    </Button>
                </DialogFooter>
            </DialogContent>
        </Dialog>
    )
});

export default AudioRecordDialog;