import { ref, onUnmounted } from 'vue';

export function useAudioRecorder() {
    const isRecording = ref(false);
    const duration = ref(0);
    const audioLevel = ref(0); // 0-1 normalized audio level
    const micDenied = ref(false);

    let mediaRecorder: MediaRecorder | null = null;
    let stream: MediaStream | null = null;
    let audioCtx: AudioContext | null = null;
    let analyser: AnalyserNode | null = null;
    let levelBuf: Uint8Array | null = null;
    let chunks: Blob[] = [];
    let timer: ReturnType<typeof setInterval> | null = null;
    let startTime = 0;

    function cleanup() {
        if (timer) { clearInterval(timer); timer = null; }
        if (audioCtx) { audioCtx.close().catch(() => {}); audioCtx = null; analyser = null; levelBuf = null; }
        if (stream) { stream.getTracks().forEach(t => t.stop()); stream = null; }
        mediaRecorder = null;
        chunks = [];
        duration.value = 0;
        audioLevel.value = 0;
        isRecording.value = false;
    }

    function updateLevel() {
        if (!analyser || !levelBuf) return;
        analyser.getByteTimeDomainData(levelBuf);
        // Compute RMS
        let sum = 0;
        for (let i = 0; i < levelBuf.length; i++) {
            const v = (levelBuf[i] - 128) / 128;
            sum += v * v;
        }
        audioLevel.value = Math.min(1, Math.sqrt(sum / levelBuf.length) * 3);
    }

    async function startRecording(): Promise<void> {
        if (isRecording.value) return;
        try {
            stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        } catch (err) {
            console.warn('[audio] mic access denied:', err);
            micDenied.value = true;
            setTimeout(() => { micDenied.value = false; }, 5000);
            return;
        }

        // Audio level analyser
        try {
            audioCtx = new AudioContext();
            const source = audioCtx.createMediaStreamSource(stream);
            analyser = audioCtx.createAnalyser();
            analyser.fftSize = 256;
            source.connect(analyser);
            levelBuf = new Uint8Array(analyser.fftSize);
        } catch (err) {
            console.warn('[audio] analyser setup failed:', err);
        }

        chunks = [];
        const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
            ? 'audio/webm;codecs=opus'
            : MediaRecorder.isTypeSupported('audio/webm')
                ? 'audio/webm'
                : '';
        mediaRecorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
        mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) chunks.push(e.data); };
        mediaRecorder.start(250);
        isRecording.value = true;
        startTime = Date.now();
        timer = setInterval(() => {
            duration.value = Math.floor((Date.now() - startTime) / 1000);
            updateLevel();
        }, 80);
    }

    function stopRecording(): Promise<File | null> {
        return new Promise((resolve) => {
            if (!mediaRecorder || mediaRecorder.state === 'inactive') {
                cleanup();
                resolve(null);
                return;
            }
            mediaRecorder.onstop = () => {
                const mimeType = mediaRecorder?.mimeType || 'audio/webm';
                const ext = mimeType.includes('mp4') ? 'mp4' : mimeType.includes('ogg') ? 'ogg' : 'webm';
                const blob = new Blob(chunks, { type: mimeType });
                const file = new File([blob], `recording-${Date.now()}.${ext}`, { type: mimeType });
                cleanup();
                resolve(file);
            };
            mediaRecorder.stop();
        });
    }

    function cancelRecording() {
        if (mediaRecorder && mediaRecorder.state !== 'inactive') {
            mediaRecorder.onstop = () => {};
            mediaRecorder.stop();
        }
        cleanup();
    }

    function formatDuration(secs: number): string {
        const m = Math.floor(secs / 60);
        const s = secs % 60;
        return `${m}:${s.toString().padStart(2, '0')}`;
    }

    onUnmounted(cleanup);

    return { isRecording, duration, audioLevel, micDenied, startRecording, stopRecording, cancelRecording, formatDuration };
}
