import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2';
import * as OpenCC from 'https://cdn.jsdelivr.net/npm/opencc-js@1.0.5/+esm';

env.allowLocalModels = false;

let progressCallback = (progress) => {
    const status = document.getElementById('status');
    if (progress.status === 'progress') {
        status.textContent = `Downloading model... ${progress.file}`;
    } else if (progress.status === 'done') {
        status.textContent = 'Model loaded';
    }
};

env.progress_callback = progressCallback;

const languageSelect = document.getElementById('language');
const recordBtn = document.getElementById('record-btn');
const stopBtn = document.getElementById('stop-btn');
const fileInput = document.getElementById('file-input');
const uploadBtn = document.getElementById('upload-btn');
const output = document.getElementById('output');
const status = document.getElementById('status');
const copyBtn = document.getElementById('copy-btn');

let recognition;
let transcriber = null;
let currentModel = null;

const getModelForLanguage = () => 'Xenova/whisper-small';

fileInput.addEventListener('change', () => {
    uploadBtn.disabled = !fileInput.files.length;
});

const extractAudio = async (file) => {
    status.textContent = `Reading file... (${(file.size / 1024 / 1024).toFixed(1)} MB)`;
    const arrayBuffer = await file.arrayBuffer();
    status.textContent = 'Decoding audio... (page may be briefly unresponsive)';
    await new Promise(r => setTimeout(r, 100));
    const audioContext = new AudioContext({ sampleRate: 16000 });
    const audioBuffer = await new Promise((resolve, reject) => {
        audioContext.decodeAudioData(arrayBuffer, resolve, reject);
    });
    status.textContent = `Audio decoded (${Math.round(audioBuffer.duration)}s)`;
    await audioContext.close();
    return audioBuffer.getChannelData(0);
};

uploadBtn.addEventListener('click', async () => {
    const file = fileInput.files[0];
    if (!file) return;

    uploadBtn.disabled = true;
    output.textContent = '';

    try {
        const selectedLang = languageSelect.value;
        const modelName = getModelForLanguage(selectedLang);

        if (!transcriber || currentModel !== modelName) {
            status.textContent = 'Downloading model...';
            transcriber = await pipeline('automatic-speech-recognition', modelName);
            currentModel = modelName;
        }

        status.textContent = 'Processing audio...';
        const audio = await extractAudio(file);

        status.textContent = 'Transcribing...';
        const langCode = selectedLang.split('-')[0];
        const result = await transcriber(audio, {
            language: langCode,
            chunk_length_s: 30,
            stride_length_s: 5,
            return_timestamps: false
        });
        let text = result.text;
        if (selectedLang === 'zh-CN') {
            const converter = OpenCC.Converter({ from: 'tw', to: 'cn' });
            text = converter(text);
        }
        output.textContent = text;
        copyBtn.style.display = 'block';
        status.textContent = 'Complete';
    } catch (err) {
        status.textContent = `Error: ${err.message}`;
    } finally {
        uploadBtn.disabled = false;
    }
});

recordBtn.addEventListener('click', async () => {
    try {
        await navigator.mediaDevices.getUserMedia({ audio: true });

        recognition = new webkitSpeechRecognition();
        recognition.continuous = true;
        recognition.interimResults = true;
        recognition.lang = languageSelect.value;

        let transcript = '';

        recognition.onresult = (event) => {
            let interim = '';
            for (let i = event.resultIndex; i < event.results.length; i++) {
                if (event.results[i].isFinal) {
                    transcript += event.results[i][0].transcript + ' ';
                } else {
                    interim += event.results[i][0].transcript;
                }
            }
            output.textContent = transcript + interim;
            copyBtn.style.display = 'block';
        };

        recognition.start();
        recordBtn.disabled = true;
        stopBtn.disabled = false;
        status.textContent = 'Recording...';

    } catch (err) {
        status.textContent = 'Microphone access denied';
    }
});

stopBtn.addEventListener('click', () => {
    if (recognition) {
        recognition.stop();
        recordBtn.disabled = false;
        stopBtn.disabled = true;
        status.textContent = 'Recording stopped';
    }
});

copyBtn.addEventListener('click', () => {
    navigator.clipboard.writeText(output.textContent);
    status.textContent = 'Copied to clipboard';
});
