import { ref, computed, watch } from 'vue';
import { useChatStore } from '../store/chat';
import { getApiBase } from '../utils/apiBase';

export interface TtsTrack {
    msgRef: any;
    sourceIndex: number;
    snippet: string;
    audioUrl: string | null;
}

type TtsState = 'idle' | 'loading' | 'playing' | 'paused';

function stripMdForTts(text: string): string {
    return text
        .replace(/```[\s\S]*?```/g, '')       // code blocks
        .replace(/`[^`]+`/g, '')               // inline code
        .replace(/!\[.*?\]\(.*?\)/g, '')       // images
        .replace(/\[([^\]]+)\]\(.*?\)/g, '$1') // links → text
        .replace(/#{1,6}\s*/g, '')             // headings
        .replace(/[*_~]+/g, '')                // bold/italic/strikethrough
        .replace(/\n{2,}/g, '. ')              // paragraph breaks → pause
        .replace(/\n/g, ' ')
        .trim();
}

function createTtsPlayer() {
    const store = useChatStore();

    const state = ref<TtsState>('idle');
    const currentTrack = ref<TtsTrack | null>(null);
    const currentTime = ref(0);
    const duration = ref(0);
    const progress = computed(() => duration.value > 0 ? currentTime.value / duration.value : 0);

    let audio: HTMLAudioElement | null = null;
    const urlCache = new Map<string, string>();

    function getAudio(): HTMLAudioElement {
        if (!audio) {
            audio = new Audio();
            audio.addEventListener('timeupdate', () => { currentTime.value = audio!.currentTime; });
            audio.addEventListener('durationchange', () => { duration.value = audio!.duration || 0; });
            audio.addEventListener('ended', () => { state.value = 'idle'; currentTrack.value = null; });
            audio.addEventListener('error', () => {
                console.error('[tts] playback error');
                state.value = 'idle'; currentTrack.value = null;
            });
        }
        return audio;
    }

    const speakableMessages = computed(() => {
        const result: { msg: any; index: number }[] = [];
        for (let i = 0; i < store.messages.length; i++) {
            const m = store.messages[i];
            if (m.role === 'assistant' && !m.streaming && m.content) {
                result.push({ msg: m, index: i });
            }
        }
        return result;
    });

    function contentKey(text: string): string {
        // Simple hash for cache key
        let h = 0;
        for (let i = 0; i < text.length; i++) { h = ((h << 5) - h + text.charCodeAt(i)) | 0; }
        return String(h);
    }

    async function play(msg: any, sourceIndex: number): Promise<void> {
        const el = getAudio(); // must be in user gesture callstack
        el.pause();

        const rawText = stripMdForTts(msg.content || '');
        if (!rawText) return;
        const text = rawText.slice(0, 4096);
        const snippet = rawText.slice(0, 60) + (rawText.length > 60 ? '...' : '');

        currentTrack.value = { msgRef: msg, sourceIndex, snippet, audioUrl: null };
        currentTime.value = 0;
        duration.value = 0;
        state.value = 'loading';

        const key = contentKey(text);
        let url = urlCache.get(key);

        if (!url) {
            try {
                const token = localStorage.getItem('nyx_session') || '';
                const apiBase = getApiBase();
                const res = await fetch(`${apiBase}/api/tts`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
                    body: JSON.stringify({ text }),
                });
                if (!res.ok) throw new Error(`TTS ${res.status}`);
                const data = await res.json();
                url = `${apiBase}${data.url}?token=${encodeURIComponent(token)}`;
                urlCache.set(key, url);
            } catch (err) {
                console.error('[tts]', err);
                state.value = 'idle';
                currentTrack.value = null;
                return;
            }
        }

        if (currentTrack.value) currentTrack.value.audioUrl = url;
        el.src = url;
        try {
            await el.play();
            state.value = 'playing';
        } catch (err) {
            console.error('[tts] play failed:', err);
            state.value = 'idle';
            currentTrack.value = null;
        }
    }

    function pause() {
        if (audio && state.value === 'playing') {
            audio.pause();
            state.value = 'paused';
        }
    }

    function resume() {
        if (audio && state.value === 'paused') {
            audio.play();
            state.value = 'playing';
        }
    }

    function stop() {
        if (audio) { audio.pause(); audio.removeAttribute('src'); audio.load(); }
        state.value = 'idle';
        currentTrack.value = null;
        currentTime.value = 0;
        duration.value = 0;
    }

    function seek(fraction: number) {
        if (audio && duration.value > 0) {
            audio.currentTime = fraction * duration.value;
        }
    }

    function nav(delta: number) {
        if (!currentTrack.value) return;
        const msgs = speakableMessages.value;
        const idx = msgs.findIndex(m => m.msg === currentTrack.value!.msgRef);
        if (idx < 0) return;
        const next = msgs[idx + delta];
        if (next) play(next.msg, next.index);
    }

    function prev() { nav(-1); }
    function next() { nav(1); }

    function isPlayingMsg(msg: any): boolean {
        return currentTrack.value?.msgRef === msg;
    }

    // Auto-stop on session reset
    watch(() => store.localSessionId, () => { stop(); urlCache.clear(); });

    return {
        state, currentTrack, currentTime, duration, progress,
        speakableMessages,
        play, pause, resume, stop, seek, prev, next,
        isPlayingMsg,
    };
}

let _instance: ReturnType<typeof createTtsPlayer> | null = null;
export function useTtsPlayer() {
    if (!_instance) _instance = createTtsPlayer();
    return _instance;
}
