import { eventSource, event_types } from "../../../script.js"
import { doExtrasFetch, getApiUrl, modules } from "../../extensions.js"
export { CoquiTtsProvider }
function throwIfModuleMissing() {
    if (!modules.includes('coqui-tts')) {
        toastr.error(`Coqui TTS module not loaded. Add coqui-tts to enable-modules and restart the Extras API.`)
        throw new Error(`Coqui TTS module not loaded.`)
    }
}
class CoquiTtsProvider {
    //########//
    // Config //
    //########//
    settings
    voices = []
    separator = ' .. '
    defaultSettings = {
        voiceMap: {}
    }
    get settingsHtml() {
        let html = `
        
        
        `
        return html
    }
    onSettingsChange() {
    }
    loadSettings(settings) {
        // Pupulate Provider UI given input settings
        if (Object.keys(settings).length == 0) {
            console.info("Using default TTS Provider settings")
        }
        const modelSelect = document.getElementById('coqui_model');
        const previewButton = document.getElementById('coqui_preview');
        previewButton.addEventListener('click', () => {
            const selectedModel = modelSelect.value;
            this.sampleTtsVoice(selectedModel);
        });//add event listener to button
        previewButton.disabled = true;
        previewButton.innerText = "Select Model";
        // Only accept keys defined in defaultSettings
        this.settings = this.defaultSettings
        for (const key in settings) {
            if (key in this.settings) {
                this.settings[key] = settings[key]
            } else {
                throw `Invalid setting passed to TTS Provider: ${key}`
            }
        }
        const textexample = document.getElementById('tts_voice_map');
        textexample.placeholder = 'Enter comma separated map of charName:ttsName[speakerID][langID]. Example: \nAqua:tts_models--en--ljspeech--glow-tts\model_file.pth,\nDarkness:tts_models--multilingual--multi-dataset--your_tts\model_file.pth[2][3]';
        //Load models function
        eventSource.on(event_types.EXTRAS_CONNECTED, () => {
            this.getModels();
        });
        this.onttsCoquiHideButtons();
        console.info("Settings loaded")
    }
    async onttsCoquiHideButtons() {
        // Get references to the select element and the two input elements
        const ttsProviderSelect = document.getElementById('tts_provider');
        const ttsVoicesInput = document.getElementById('tts_voices');
        const ttsPreviewInput = document.getElementById('tts_preview');
        ttsProviderSelect.addEventListener('click', () => {
            this.getModels();
         });
        // Add an event listener to the 'change' event of the tts_provider select element
        ttsProviderSelect.addEventListener('change', () => {
            // Check if the selected value is 'Coqui'
            if (ttsProviderSelect.value === 'Coqui') {
                ttsVoicesInput.style.display = 'none'; // Hide the tts_voices input
                ttsPreviewInput.style.display = ''; // Show the tts_preview input
            } else {
                ttsVoicesInput.style.display = ''; // Show the tts_voices input
                ttsPreviewInput.style.display = 'none'; // Hide the tts_preview input
            }
        });
    }
    async onApplyClick() {
        return
    }
    async getLang() {
        try {
            const response = await doExtrasFetch(`${getApiUrl()}/api/coqui-tts/multlang`);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            const voiceData = await response.json();
            const languageSelect = document.getElementById('coqui_language');
            languageSelect.innerHTML = ''; // Clear existing options
            if (Object.keys(voiceData).length === 0) {
                const option = document.createElement('option');
                option.value = 'none';
                option.textContent = 'None';
                languageSelect.appendChild(option);
            } else {
                for (const [key, value] of Object.entries(voiceData)) {
                    const option = document.createElement('option');
                    option.value = key;
                    option.textContent = key + ": " + value;
                    languageSelect.appendChild(option);
                }
            }
        } catch (error) {
            //console.error('Error fetching voice data:', error);
            // Remove all options except "None"
            const languageSelect = document.getElementById('coqui_language');
            languageSelect.innerHTML = '';
            const option = document.createElement('option');
            option.value = 'none';
            option.textContent = 'None';
            languageSelect.appendChild(option);
        }
    }
    async getSpeakers() {
        try {
            const response = await doExtrasFetch(`${getApiUrl()}/api/coqui-tts/multspeaker`);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            const voiceData = await response.json();
            const speakerSelect = document.getElementById('coqui_speaker');
            speakerSelect.innerHTML = ''; // Clear existing options
            if (Object.keys(voiceData).length === 0) {
                const option = document.createElement('option');
                option.value = 'none';
                option.textContent = 'None';
                speakerSelect.appendChild(option);
            } else {
                for (const [index, name] of Object.entries(voiceData)) {
                    const option = document.createElement('option');
                    option.value = index;
                    option.textContent = index + ": " + name;
                    speakerSelect.appendChild(option);
                }
            }
        } catch (error) {
            //console.error('Error fetching voice data:', error);
            // Remove all options except "None"
            const speakerSelect = document.getElementById('coqui_speaker');
            speakerSelect.innerHTML = '';
            const option = document.createElement('option');
            option.value = 'none';
            option.textContent = 'None';
            speakerSelect.appendChild(option);
        }
    }
    async getModels() {
        try {
            throwIfModuleMissing();
            const response = await doExtrasFetch(`${getApiUrl()}/api/coqui-tts/list`);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            const voiceIds = await response.json();
            const modelSelect = document.getElementById('coqui_model');
            if (voiceIds.length === 0) {
                const option = document.createElement('option');
                option.value = 'none';
                option.textContent = 'Select Model';
                modelSelect.appendChild(option);
            } else {
                voiceIds.forEach(voiceId => {
                    const option = document.createElement('option');
                    option.value = voiceId;
                    option.textContent = voiceId;
                    modelSelect.appendChild(option);
                });
            }
            // Update provider endpoint on model selection change
            modelSelect.addEventListener('change', () => {
                const selectedModel = modelSelect.value;
                this.LoadModel(selectedModel);
            });
        } catch (error) {
            console.error('Error fetching voice IDs:', error);
            // Add "None" option when the request fails or the response is empty
            const modelSelect = document.getElementById('coqui_model');
            const option = document.createElement('option');
            option.value = 'none';
            option.textContent = 'None';
            modelSelect.appendChild(option);
        }
    }
    async LoadModel(selectedModel) {
        const previewButton = document.getElementById('coqui_preview');
        previewButton.disabled = true;
        previewButton.innerText = "Loading";
        try {
            throwIfModuleMissing();
            const response = await doExtrasFetch(`${getApiUrl()}/api/coqui-tts/load?_model=${selectedModel}`);
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            this.getSpeakers();
            this.getLang();
            const previewButton = document.getElementById('coqui_preview');
            previewButton.disabled = false;
            previewButton.innerText = "Play";
        } catch (error) {
            console.error('Error updating provider endpoint:', error);
        }
    }
    async getVoice(voiceName) {
        //tts_models--multilingual--multi-dataset--your_tts\model_file.pth[2][1]
        //tts_models--en--ljspeech--glow-tts\model_file.pth
        let _voiceNameOrg = voiceName; // Store the original voiceName in a variable _voiceNameOrg
        voiceName = voiceName.replace(/(\[\d+\])+$/, ''); // For example, converts 'model[2][1]' to 'model'
        this.voices = []; //reset for follow up runs
        if (this.voices.length === 0) { this.voices = await this.fetchCheckMap(); }
        // Search for a voice object in the 'this.voices' array where the 'name' property matches the provided 'voiceName'
        //const match = this.voices.find((CoquiVoice) => CoquiVoice.name === voiceName);
        const match = this.voices.find((CoquiVoice) => CoquiVoice.name === voiceName);
        // If no match is found, throw an error indicating that the TTS Voice name was not found
        if (!match) {
            throw new Error(`TTS Voice name ${voiceName} not found`);
        } else {
            match.name = _voiceNameOrg;
            match.voice_id = _voiceNameOrg;
        }
        // Return the matched voice object (with the 'name' property updated if a match was found)
        return match;
    }
    async fetchCheckMap() {
        const endpoint = `${getApiUrl()}/api/coqui-tts/checkmap`;
        const response = await doExtrasFetch(endpoint);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${await response.json()}`);
        }
        const voiceData = await response.json();
        const voices = voiceData.map((voice) => ({
            id: voice.name,
            name: voice.id, // this is the issue!!!
            voice_id: voice.id, // this is the issue!!!
            //preview_url: false,
            lang: voice.lang,
        }));
        return voices;
    }
    async fetchTtsVoiceIds() {
        throwIfModuleMissing();
        const endpoint = `${getApiUrl()}/api/coqui-tts/speaker_id`;
        const response = await doExtrasFetch(endpoint);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${await response.json()}`);
        }
        const voiceData = await response.json();
        const voices = voiceData.map((voice) => ({
            id: voice.name,
            name: voice.id, //add filename here
            voice_id: voice.id,
            //preview_url: false,
            //preview_url: `${getApiUrl()}/api/coqui-tts/download?model=${voice.id}`,
            //http://localhost:5100/api/coqui-tts/speaker_id/tts_models/en/ljspeech/speedy-speech
            lang: voice.lang,
        }));
        return voices;
    }
    sampleTtsVoice(voiceId) {
        // Get the selected values of speaker and language
        const speakerSelect = document.getElementById('coqui_speaker');
        const languageSelect = document.getElementById('coqui_language');
        const selectedSpeaker = speakerSelect.value;
        const selectedLanguage = languageSelect.value;
        // Construct the URL with the selected values
        const url = `${getApiUrl()}/api/coqui-tts/tts?text=The%20Quick%20Brown%20Fox%20Jumps%20Over%20the%20Lazy%20Dog.&speaker_id=${voiceId}&style_wav=&language_id=${selectedLanguage}&mspker=${selectedSpeaker}`;
        doExtrasFetch(url)
            .then(response => response.blob())
            .then(blob => {
                const audioUrl = URL.createObjectURL(blob);
                // Play the audio
                const audio = new Audio(audioUrl);
                audio.play();
            })
            .catch(error => {
                console.error('Error performing TTS request:', error);
            });
    }
    previewTtsVoice(voiceId) { //button on avail voices
        throwIfModuleMissing();
        const url = `${getApiUrl()}/api/coqui-tts/download?model=${voiceId}`;
        doExtrasFetch(url)
            .then(response => response.text()) // Expecting a text response
            .then(responseText => {
                const isResponseTrue = responseText.trim().toLowerCase() === 'true';
                if (isResponseTrue) {
                    console.log("Downloading Model") //if true
                } else {
                    console.error('Already Installed'); //if false
                }
            })
            .catch(error => {
                console.error('Error performing download:', error);
            });
    }
    async generateTts(text, voiceId) {
        const response = await this.fetchTtsGeneration(text, voiceId)
        return response
    }
    async fetchTtsGeneration(inputText, voiceId) {
        throwIfModuleMissing();
        console.info(`Generating new TTS for voice_id ${voiceId}`);
        const response = await doExtrasFetch(`${getApiUrl()}/api/coqui-tts/tts?text=${encodeURIComponent(inputText)}&speaker_id=${voiceId}`);
        if (!response.ok) {
            toastr.error(response.statusText, 'TTS Generation Failed');
            throw new Error(`HTTP ${response.status}: ${await response.text()}`);
        }
        if (!response.ok) {
            toastr.error(response.statusText, 'TTS Generation Failed');
            throw new Error(`HTTP ${response.status}: ${await response.text()}`);
        }
        return response
    }
    async fetchTtsFromHistory(history_item_id) {
        return Promise.resolve(history_item_id);
    }
}