/**
 * RunningHub TTS API 语音合成模块
 * 文档: https://www.runninghub.cn/runninghub-api-doc-cn/api-279098421
 */

import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';
import { spawn } from 'child_process';
import { app } from 'electron';
import logger from '../log/main';
import { getFFmpegExecutablePath, resourceExists } from '../../lib/resource-path';
import { fetchElectronSystemConfig } from '../systemConfig';

const BASE_URL = 'https://www.runninghub.cn';
const WEBAPP_ID_V2 = '1965614643077070850';  // TTS V2 应用ID
const WEBAPP_ID_V3 = '2028779949334728706';  // TTS V3 应用ID（中文最强）

const DEFAULT_TTS_V2_NODES = {
    audio: '13',
    text: '14',
    emotion: '15',
};

export interface RunningHubConfig {
    apiKey: string;
    audioFileName: string;   // 克隆音频文件名（需先上传到RunningHub）
    emotion?: string;        // 情感描述，如"害羞的"、"开心的"
    outputPath?: string;     // 自定义输出路径
    version?: 'v2' | 'v3';   // TTS版本：v2 或 v3（中文最强），默认v2
}

const RUNNINGHUB_EMOTION_ALIASES: Record<string, string> = {
    '开心': '开心的',
    '悲伤': '悲伤的',
    '愤怒': '愤怒的',
    '恐惧': '恐惧的',
    '惊讶': '惊讶的',
    '厌恶': '厌恶的',
    '害羞': '害羞的',
    '温柔': '温柔的',
    '激动': '激动的',
    '平静': '平静的',
    '自然': '自然、平静、克制的',
};

function normalizeEmotionPrompt(emotion?: string): string | undefined {
    const value = String(emotion || '').trim();
    if (!value || value === '无' || value.toLowerCase() === 'none') {
        return undefined;
    }
    return RUNNINGHUB_EMOTION_ALIASES[value] || value;
}

function normalizeSpeed(speed?: number): number {
    const parsed = Number(speed);
    if (!Number.isFinite(parsed) || parsed <= 0) {
        return 1;
    }
    return Math.min(2, Math.max(0.5, parsed));
}

function getRunningHubErrorText(error: any): string {
    const data = error?.response?.data;
    if (!data) {
        return error?.message || '';
    }
    if (typeof data === 'string') {
        return data;
    }
    const nested = data.data && typeof data.data === 'object' ? data.data : {};
    return [
        data.msg,
        data.message,
        data.errorMessage,
        data.error,
        data.code,
        nested.msg,
        nested.message,
        nested.errorMessage,
        nested.error,
        nested.code,
    ].filter(Boolean).join(' | ') || JSON.stringify(data);
}

function isFieldMismatchForNode(error: any, nodeId?: string, fieldName?: string): boolean {
    const text = getRunningHubErrorText(error);
    return text.includes('NODE_INFO_MISMATCH')
        && (!nodeId || text.includes(`nodeId=${nodeId}`))
        && (!fieldName || text.includes(`fieldName=${fieldName}`));
}

function buildAtempoFilterChain(speed: number): string {
    const filters: string[] = [];
    let remaining = speed;

    while (remaining > 2) {
        filters.push('atempo=2');
        remaining /= 2;
    }
    while (remaining < 0.5) {
        filters.push('atempo=0.5');
        remaining /= 0.5;
    }

    filters.push(`atempo=${remaining.toFixed(3)}`);
    return filters.join(',');
}

function runFFmpeg(ffmpegPath: string, args: string[]): Promise<void> {
    return new Promise((resolve, reject) => {
        const proc = spawn(ffmpegPath, args);
        let stderr = '';

        proc.stderr.on('data', (data: Buffer) => {
            stderr += data.toString();
        });
        proc.on('close', (code) => {
            if (code === 0) {
                resolve();
                return;
            }
            reject(new Error(stderr || `FFmpeg exited with code ${code}`));
        });
        proc.on('error', reject);
    });
}

async function adjustAudioSpeedIfNeeded(filePath: string, speed?: number): Promise<string> {
    const normalizedSpeed = normalizeSpeed(speed);
    if (Math.abs(normalizedSpeed - 1) < 0.01) {
        return filePath;
    }

    const ffmpegPath = getFFmpegExecutablePath();
    if (!resourceExists(ffmpegPath)) {
        logger.warn('[RunningHub] FFmpeg missing, skip speed post-process', {
            filePath,
            normalizedSpeed,
        });
        return filePath;
    }

    const ext = path.extname(filePath) || '.mp3';
    const tempOutputPath = path.join(
        path.dirname(filePath),
        `${path.basename(filePath, ext)}_speed${ext}`
    );

    await runFFmpeg(ffmpegPath, [
        '-y',
        '-i', filePath,
        '-vn',
        '-filter:a', buildAtempoFilterChain(normalizedSpeed),
        tempOutputPath,
    ]);

    fs.rmSync(filePath, { force: true });
    fs.renameSync(tempOutputPath, filePath);

    logger.info('[RunningHub] Speed post-process done', { filePath, normalizedSpeed });
    return filePath;
}

export interface RunningHubResult {
    success: boolean;
    audioPath?: string;
    error?: string;
    taskId?: string;
}

/**
 * 发起TTS任务
 */
async function submitTask(
    text: string,
    config: RunningHubConfig
): Promise<{ success: boolean; taskId?: string; error?: string }> {
    try {
        const sysCfg = await fetchElectronSystemConfig();
        const version = config.version || 'v2';
        const webappId = version === 'v3'
            ? (sysCfg.runninghub_tts_webapp_id_v3 || WEBAPP_ID_V3)
            : (sysCfg.runninghub_tts_webapp_id_v2 || WEBAPP_ID_V2);
        const v2Nodes = {
            audio: sysCfg.runninghub_tts_v2_audio_node || DEFAULT_TTS_V2_NODES.audio,
            text: sysCfg.runninghub_tts_v2_text_node || DEFAULT_TTS_V2_NODES.text,
            emotion: sysCfg.runninghub_tts_v2_emotion_node || DEFAULT_TTS_V2_NODES.emotion,
        };
        const normalizedEmotion = normalizeEmotionPrompt(config.emotion);
        const normalizedSpeed = normalizeSpeed((config as any).speed);

        logger.info('[RunningHub] 提交TTS任务', {
            version,
            webappId,
            text: text.substring(0, 50),
            emotion: normalizedEmotion,
            speed: normalizedSpeed
        });

        let nodeInfoList: any[];

        if (version === 'v3') {
            // V3 节点配置（根据文档 2028779949334728706）
            nodeInfoList = [
                {
                    nodeId: "5",
                    fieldName: "audio",
                    fieldValue: config.audioFileName,
                    description: "需要克隆的语音"
                },
                {
                    nodeId: "4",
                    fieldName: "prompt",
                    fieldValue: text,
                    description: "文字"
                }
            ];
        } else {
            // V2 节点配置（原有配置）
            nodeInfoList = [
                {
                    nodeId: v2Nodes.audio,
                    fieldName: "audio",
                    fieldValue: config.audioFileName,
                    description: "上传克隆音频"
                },
                {
                    nodeId: v2Nodes.text,
                    fieldName: "value",
                    fieldValue: text,
                    description: "上传语音文本"
                }
            ];

            // V2 如果有情感描述，添加情感节点
            if (v2Nodes.emotion && normalizedEmotion) {
                nodeInfoList.push({
                    nodeId: v2Nodes.emotion,
                    fieldName: "value",
                    fieldValue: normalizedEmotion || "",
                    description: "情感描述"
                });
            }
        }

        const postTask = (nodes: any[]) => axios.post(
            `${BASE_URL}/openapi/v2/run/ai-app/${webappId}`,
            {
                nodeInfoList: nodes,
                instanceType: version === 'v2' ? "default" : "plus",
                usePersonalQueue: "false"
            },
            {
                headers: {
                    'Host': 'www.runninghub.cn',
                    'Authorization': `Bearer ${config.apiKey}`,
                    'Content-Type': 'application/json'
                },
                timeout: 30000
            }
        );

        let response;
        try {
            response = await postTask(nodeInfoList);
        } catch (error: any) {
            if (version === 'v2' && v2Nodes.emotion && isFieldMismatchForNode(error, v2Nodes.emotion, 'value')) {
                const retryNodeInfoList = nodeInfoList.filter(node => String(node.nodeId) !== String(v2Nodes.emotion));
                logger.warn('[RunningHub] Emotion node value field mismatch, retry without emotion node', {
                    emotionNode: v2Nodes.emotion,
                    error: getRunningHubErrorText(error),
                });
                response = await postTask(retryNodeInfoList);
            } else {
                throw error;
            }
        }

        // 兼容 V2 和 V3 的响应格式
        let taskId = response.data?.taskId || response.data?.data?.taskId;
        let status = response.data?.status || response.data?.data?.taskStatus;
        const hasEmotionNode = nodeInfoList.some(node => String(node.nodeId) === String(v2Nodes.emotion));
        if (!taskId && version === 'v2' && hasEmotionNode && isFieldMismatchForNode({ response: { data: response.data } }, v2Nodes.emotion, 'value')) {
            logger.warn('[RunningHub] Emotion node value field mismatch in response, retry without emotion node', {
                emotionNode: v2Nodes.emotion,
                error: getRunningHubErrorText({ response: { data: response.data } }),
            });
            response = await postTask(nodeInfoList.filter(node => String(node.nodeId) !== String(v2Nodes.emotion)));
            taskId = response.data?.taskId || response.data?.data?.taskId;
            status = response.data?.status || response.data?.data?.taskStatus;
        }

        if (taskId) {
            logger.info('[RunningHub] 任务提交成功', {
                version,
                taskId,
                status
            });
            return {
                success: true,
                taskId
            };
        } else {
            logger.error('[RunningHub] 任务提交失败', response.data);
            return {
                success: false,
                error: response.data?.errorMessage || response.data?.msg || response.data?.message || '任务提交失败'
            };
        }

    } catch (error: any) {
        logger.error('[RunningHub] 任务提交异常', error);
        const errorMsg = getRunningHubErrorText(error) || '未知错误';
        return { success: false, error: errorMsg };
    }
}

/**
 * 查询任务结果
 */
async function queryTaskResult(
    taskId: string,
    apiKey: string
): Promise<{
    success: boolean;
    status?: string;
    outputs?: any[];
    error?: string
}> {
    try {
        logger.info('[RunningHub] 查询任务状态', { taskId });

        const response = await axios.post(
            `${BASE_URL}/openapi/v2/query`,
            { taskId, apiKey },
            {
                headers: {
                    'Host': 'www.runninghub.cn',
                    'Authorization': `Bearer ${apiKey}`,
                    'Content-Type': 'application/json'
                },
                timeout: 30000
            }
        );

        // 打印完整响应便于调试
        logger.info('[RunningHub] 查询响应原始数据', JSON.stringify(response.data));

        // 尝试从不同字段获取状态（兼容不同API版本）
        // 尝试从不同字段获取状态（兼容不同API版本）
        const data = response.data?.data || response.data;
        const status = data?.taskStatus || data?.status;
        const outputs = data?.outputs || data?.results;

        // API直接返回{status, results}格式，不需要检查code
        if (status) {
            return {
                success: true,
                status: status,
                outputs: outputs
            };
        } else {
            return {
                success: false,
                error: response.data?.msg || response.data?.errorMessage || '查询失败'
            };
        }

    } catch (error: any) {
        logger.error('[RunningHub] 查询任务异常', error);
        return {
            success: false,
            error: error.response?.data?.msg || error.message
        };
    }
}

/**
 * 等待任务完成
 */
async function waitForTaskCompletion(
    taskId: string,
    apiKey: string,
    maxWaitTime: number = 3600000,  // 最长等待60分钟
    pollInterval: number = 3000    // 每3秒轮询一次
): Promise<{ success: boolean; outputs?: any[]; error?: string }> {
    const startTime = Date.now();

    while (Date.now() - startTime < maxWaitTime) {
        const result = await queryTaskResult(taskId, apiKey);

        if (!result.success) {
            return { success: false, error: result.error };
        }

        logger.info('[RunningHub] 任务状态', {
            taskId,
            status: result.status,
            elapsed: Date.now() - startTime
        });

        if (result.status === 'SUCCESS' || result.status === 'COMPLETED') {
            return { success: true, outputs: result.outputs };
        }

        if (result.status === 'FAILED' || result.status === 'ERROR') {
            return { success: false, error: '任务执行失败' };
        }

        // 等待后继续轮询
        await new Promise(resolve => setTimeout(resolve, pollInterval));
    }

    return { success: false, error: '任务超时' };
}

/**
 * 下载音频文件
 */
async function downloadAudio(
    url: string,
    outputPath: string
): Promise<boolean> {
    try {
        const response = await axios.get(url, {
            responseType: 'arraybuffer',
            timeout: 60000
        });

        // 确保输出目录存在
        const outputDir = path.dirname(outputPath);
        if (!fs.existsSync(outputDir)) {
            fs.mkdirSync(outputDir, { recursive: true });
        }

        fs.writeFileSync(outputPath, response.data);
        logger.info('[RunningHub] 音频下载成功', { outputPath });
        return true;

    } catch (error: any) {
        logger.error('[RunningHub] 音频下载失败', error);
        return false;
    }
}

/**
 * RunningHub TTS 语音合成主函数
 */
export async function synthesizeSpeech(
    text: string,
    config: RunningHubConfig
): Promise<RunningHubResult> {
    logger.info('[RunningHub] 开始语音合成', {
        text: text.substring(0, 50),
        audioFileName: config.audioFileName,
        emotion: normalizeEmotionPrompt(config.emotion),
        speed: normalizeSpeed((config as any).speed)
    });

    // 1. 提交任务
    const submitResult = await submitTask(text, config);
    if (!submitResult.success || !submitResult.taskId) {
        return {
            success: false,
            error: submitResult.error || '任务提交失败'
        };
    }

    const taskId = submitResult.taskId;

    // 2. 等待任务完成
    const completionResult = await waitForTaskCompletion(taskId, config.apiKey);
    if (!completionResult.success) {
        return {
            success: false,
            error: completionResult.error,
            taskId
        };
    }

    // 3. 获取音频URL
    const outputs = completionResult.outputs || [];
    let audioUrl: string | null = null;

    // 遍历outputs找到音频文件
    for (const output of outputs) {
        // 使用url或fileUrl字段
        const url = output.url || output.fileUrl;
        if (url && (
            url.endsWith('.mp3') ||
            url.endsWith('.wav') ||
            url.endsWith('.flac') ||  // 添加flac支持
            output.outputType === 'flac' ||
            output.outputType === 'audio' ||
            output.fileType === 'audio'
        )) {
            audioUrl = url;
            break;
        }
    }

    if (!audioUrl) {
        logger.error('[RunningHub] 未找到音频输出', { outputs });
        return {
            success: false,
            error: '未找到音频输出',
            taskId
        };
    }

    // 4. 下载音频
    let outputPath: string;
    if (config.outputPath) {
        outputPath = config.outputPath;
    } else {
        const outputDir = path.join(app.getPath('userData'), 'temp', 'tts');
        if (!fs.existsSync(outputDir)) {
            fs.mkdirSync(outputDir, { recursive: true });
        }
        const ext = path.extname(audioUrl) || '.mp3';
        outputPath = path.join(outputDir, `runninghub_${Date.now()}${ext}`);
    }

    const downloaded = await downloadAudio(audioUrl, outputPath);
    if (!downloaded) {
        return {
            success: false,
            error: '音频下载失败',
            taskId
        };
    }

    logger.info('[RunningHub] 语音合成完成', { outputPath, taskId });
    outputPath = await adjustAudioSpeedIfNeeded(outputPath, (config as any).speed);

    return {
        success: true,
        audioPath: outputPath,
        taskId
    };
}

/**
 * 获取可用的情感描述列表
 */
export function getAvailableEmotions(): Array<{ id: string; name: string; desc: string }> {
    return [
        { id: '', name: '无', desc: '不指定情感' },
        { id: '开心的', name: '开心', desc: '愉快欢乐' },
        { id: '悲伤的', name: '悲伤', desc: '伤心难过' },
        { id: '愤怒的', name: '愤怒', desc: '生气恼怒' },
        { id: '害羞的', name: '害羞', desc: '羞涩腼腆' },
        { id: '温柔的', name: '温柔', desc: '轻柔亲切' },
        { id: '激动的', name: '激动', desc: '激昂兴奋' },
        { id: '平静的', name: '平静', desc: '冷静沉稳' },
        { id: '惊讶的', name: '惊讶', desc: '吃惊意外' },
        { id: '恐惧的', name: '恐惧', desc: '害怕担忧' }
    ];
}
