import chalk from 'chalk';
import * as fs from 'fs';
import * as path from 'path';
export class MusicCommand {
    config;
    logger;
    constructor(config, logger) {
        this.config = config;
        this.logger = logger;
    }
    apiBase() {
        const configured = String(this.config.getAll().musicApiUrl || '').trim();
        return (process.env.VIGTHORIA_MUSIC_API_URL || configured || 'https://music.vigthoria.io').replace(/\/+$/, '');
    }
    authHeaders() {
        const token = this.config.get('authToken');
        return token ? { Authorization: `Bearer ${token}` } : {};
    }
    async request(endpoint, init = {}) {
        const response = await fetch(`${this.apiBase()}${endpoint}`, {
            ...init,
            headers: {
                ...this.authHeaders(),
                ...init.headers,
            },
        });
        const text = await response.text();
        let data = {};
        try {
            data = text ? JSON.parse(text) : {};
        }
        catch {
            data = { message: text };
        }
        if (!response.ok) {
            throw new Error(String(data.error || data.message || `Music API request failed: ${response.status}`));
        }
        return data;
    }
    async uploadVoiceReference(filePath) {
        const absolutePath = path.resolve(filePath);
        if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) {
            throw new Error(`Voice reference file not found: ${filePath}`);
        }
        const form = new FormData();
        const blob = new Blob([fs.readFileSync(absolutePath)]);
        form.append('audio', blob, path.basename(absolutePath));
        const data = await this.request('/api/voice/upload', {
            method: 'POST',
            body: form,
        });
        const referencePath = String(data.reference_audio_path || data.path || data.file_path || '').trim();
        if (!referencePath) {
            throw new Error('Voice upload succeeded but did not return a reference_audio_path.');
        }
        return referencePath;
    }
    async generate(promptArg, options) {
        const prompt = String(promptArg || options.prompt || '').trim();
        if (!prompt) {
            throw new Error('Music generation requires a prompt.');
        }
        let referenceAudioPath = '';
        if (options.voice) {
            referenceAudioPath = await this.uploadVoiceReference(options.voice);
        }
        const duration = Math.max(1, Number(options.duration || 120));
        const payload = {
            prompt,
            language: options.language || 'en',
            voice_type: options.voiceType || 'female',
            genre: options.genre || 'pop',
            style_tags: options.styleTags || '',
            lyrics: options.lyrics || undefined,
            duration,
            engine: 'v4',
            is_preview: false,
        };
        if (referenceAudioPath) {
            payload.voice_cloning = {
                enabled: true,
                reference_audio_path: referenceAudioPath,
            };
        }
        const data = await this.request('/api/quick/generate', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
        });
        const taskId = String(data.task_id || data.session_id || '').trim();
        if (options.json) {
            console.log(JSON.stringify({ ...data, task_id: taskId || data.task_id }, null, 2));
        }
        else {
            console.log(chalk.green('Music generation queued.'));
            console.log(chalk.cyan('Task ID: ') + (taskId || '(pending)'));
            if (data.queue_position)
                console.log(chalk.gray(`Queue position: ${data.queue_position}`));
            if (data.estimated_wait_seconds)
                console.log(chalk.gray(`Estimated wait: ${data.estimated_wait_seconds}s`));
        }
        if (options.wait && taskId) {
            await this.waitForStatus(taskId, Number(options.pollInterval || 5), Boolean(options.json));
        }
    }
    async status(taskId, options = {}) {
        const data = await this.request(`/api/status/${encodeURIComponent(taskId)}`);
        if (options.json) {
            console.log(JSON.stringify(data, null, 2));
            return;
        }
        console.log(chalk.cyan(`Music task ${taskId}`));
        console.log(`Status: ${data.status || 'unknown'}`);
        if (data.progress !== undefined)
            console.log(`Progress: ${data.progress}%`);
        const downloadUrl = data.download_url || data.audio_url || data.file_url || data.result_url;
        if (downloadUrl)
            console.log(`Download: ${downloadUrl}`);
    }
    async waitForStatus(taskId, intervalSeconds, json) {
        const delay = Math.max(1, intervalSeconds) * 1000;
        for (;;) {
            await new Promise((resolve) => setTimeout(resolve, delay));
            const data = await this.request(`/api/status/${encodeURIComponent(taskId)}`);
            const status = String(data.status || '').toLowerCase();
            if (!json) {
                const progress = data.progress !== undefined ? ` (${data.progress}%)` : '';
                console.log(chalk.gray(`Status: ${status || 'unknown'}${progress}`));
            }
            if (['completed', 'complete', 'finished', 'failed', 'error', 'cancelled'].includes(status)) {
                if (json)
                    console.log(JSON.stringify(data, null, 2));
                return;
            }
        }
    }
}
