import { ipcMain } from "electron";
import shellApi, { buildRuntimeProcessEnv } from "./index";
import { Log } from "../log";
import { normalizePath } from "../../lib/path-util";
import { ProcessCleanupManager } from "../../lib/process-cleanup";

console.log("[shell/main.ts] Module loaded, registering IPC handlers...");

// 注册 showItemInFolder handler
ipcMain.handle("shell:showItemInFolder", async (event, filePath: string) => {
    return shellApi.showItemInFolder(filePath);
});

// 注册 exec handler (用于执行系统命令如 python、nvidia-smi、taskkill 等)
ipcMain.handle("shell:exec", async (event, command: string) => {
    console.log("[shell:exec] Handler called, command:", command.substring(0, 100) + (command.length > 100 ? '...' : ''));
    Log.info("shell:exec.start", { command: command.substring(0, 200) + '...' });

    try {
        const { spawn } = await import('child_process');
        const { AppEnv, waitAppEnvReady } = await import('../env');

        // 等待AppEnv初始化完成
        await waitAppEnvReady();

        // 获取工作目录
        const cwd = AppEnv.appRoot || process.cwd();

        return new Promise((resolve, reject) => {
            console.log('[shell.exec] 执行命令:', command);

            const child = spawn(command, [], {
                cwd,
                shell: true,
                env: buildRuntimeProcessEnv(),
                stdio: ['pipe', 'pipe', 'pipe'],
            });

            // 注册子进程到清理管理器
            if (child.pid) {
                ProcessCleanupManager.registerChildProcess(child.pid);
            }

            let stdout = '';
            let stderr = '';

            child.stdout?.on('data', (data) => {
                stdout += data.toString();
            });

            child.stderr?.on('data', (data) => {
                stderr += data.toString();
            });

            child.on('close', (code) => {
                // 进程结束时注销
                if (child.pid) {
                    ProcessCleanupManager.unregisterChildProcess(child.pid);
                }
                console.log('[shell.exec] 命令完成，退出码:', code);
                if (code === 0) {
                    resolve(stdout);
                } else {
                    console.warn('[shell.exec] 命令执行失败，退出码:', code, 'stderr:', stderr);
                    resolve(stdout); // 返回stdout而不是抛出错误，保持与旧版本兼容
                }
            });

            child.on('error', (error) => {
                // 进程错误时注销
                if (child.pid) {
                    ProcessCleanupManager.unregisterChildProcess(child.pid);
                }
                console.error('[shell.exec] 进程错误:', error);
                reject(error);
            });
        });
    } catch (error: any) {
        Log.error("shell:exec.error", {
            error: error?.message || String(error),
            command: command.substring(0, 200) + '...'
        });
        throw error;
    }
});

// 注册 getPythonPath handler
ipcMain.handle("shell:getPythonPath", async (event) => {
    console.log("[shell:getPythonPath] Handler called");
    Log.info("shell:getPythonPath.start");

    try {
        return await shellApi.getPythonPath();
    } catch (error: any) {
        Log.error("shell:getPythonPath.error", {
            error: error?.message || String(error)
        });
        throw error;
    }
});

// 注册 executeFFmpeg handler
ipcMain.handle("shell:executeFFmpeg", async (event, commandOrJson: string) => {
    console.log("[shell:executeFFmpeg] Handler called, command length:", commandOrJson.length);
    Log.info("shell:executeFFmpeg.start", { commandLength: commandOrJson.length });

    try {
        // 检查是否是JSON数组格式（args数组模式，避免路径拼接问题）
        if (commandOrJson.startsWith('[')) {
            const argsArray = JSON.parse(commandOrJson);
            if (Array.isArray(argsArray)) {
                Log.info("shell:executeFFmpeg.arrayMode", {
                    argsCount: argsArray.length
                });
                return await shellApi.execFFmpegCommand(argsArray);
            }
        }

        // 检查是否是JSON格式（长过滤器模式）
        if (commandOrJson.startsWith('{')) {
            const data = JSON.parse(commandOrJson);

            if (data.type === 'ffmpeg_long_filter') {
                Log.info("shell:executeFFmpeg.longFilter", {
                    inputVideo: data.inputVideo,
                    outputVideo: data.outputVideo,
                    filterLength: data.filterComplex.length,
                    hasAudioMix: !!data.audioMixConfig  // 🆕 记录是否有音效混音
                });

                // 🔧 转换输入输出路径
                const { AppEnv, waitAppEnvReady } = await import('../env');
                await waitAppEnvReady();
                const ffmpegCwd = AppEnv.installRoot || AppEnv.appRoot || process.cwd();

                const normalizedInputVideo = normalizePath(data.inputVideo);
                const normalizedOutputVideo = normalizePath(data.outputVideo);

                Log.info("shell:executeFFmpeg.pathNormalized", {
                    originalInput: data.inputVideo.substring(0, 100),
                    normalizedInput: normalizedInputVideo.substring(0, 100),
                    originalOutput: data.outputVideo.substring(0, 100),
                    normalizedOutput: normalizedOutputVideo.substring(0, 100)
                });

                // 【修复】如果filter_complex过长，写入文件使用新语法 -/filter_complex
                // 避免Windows命令行长度限制（某些情况下单个参数>32KB会失败）
                // 注意：FFmpeg N-122209 已弃用 -filter_complex_script，改用 -/filter_complex
                const { promises: fs } = await import('fs');
                const path = await import('path');
                const os = await import('os');

                // 🆕 处理音效混音配置
                const audioMixConfig = data.audioMixConfig;
                let finalFilterContent = data.filterComplex;
                let audioInputArgs: string[] = [];
                let useAudioMix = false;

                if (audioMixConfig && audioMixConfig.inputFiles && audioMixConfig.inputFiles.length > 0) {
                    console.log(`[shell:executeFFmpeg] 🔊 检测到音效混音配置:`, {
                        inputFilesCount: audioMixConfig.inputFiles.length,
                        mixFilter: audioMixConfig.mixFilter
                    });

                    // 🔧 转换音效文件路径并添加为额外输入
                    for (const soundFile of audioMixConfig.inputFiles) {
                        const normalizedSoundFile = normalizePath(soundFile);
                        audioInputArgs.push('-i', normalizedSoundFile);
                        Log.info("shell:executeFFmpeg.soundFileNormalized", {
                            original: soundFile.substring(0, 100),
                            normalized: normalizedSoundFile.substring(0, 100)
                        });
                    }

                    // 🔧 关键修复：修改视频滤镜链的末尾，添加 [vout] 输出标签
                    // 原始滤镜链末尾没有输出标签，例如：[outN]drawtext=...
                    // 需要改为：[outN]drawtext=...[vout]
                    // 然后添加音频混音滤镜

                    let modifiedVideoFilter = data.filterComplex;

                    // 检查最后一个滤镜是否已有输出标签
                    // 如果没有，添加 [vout]
                    if (!modifiedVideoFilter.endsWith(']')) {
                        // 最后一个滤镜没有输出标签，添加 [vout]
                        modifiedVideoFilter = modifiedVideoFilter + '[vout]';
                        console.log(`[shell:executeFFmpeg] 🔊 添加视频输出标签 [vout]`);
                    } else {
                        // 最后一个滤镜已有输出标签（可能是 [out0]、[out1] 等）
                        // 需要提取这个标签名称，然后添加一个 null 滤镜连接到 [vout]
                        // 从滤镜链末尾提取最后一个输出标签，例如 [out5]
                        const lastLabelMatch = modifiedVideoFilter.match(/\[([^\[\]]+)\]$/);
                        if (lastLabelMatch) {
                            const lastLabel = lastLabelMatch[1];
                            modifiedVideoFilter = modifiedVideoFilter + `;[${lastLabel}]null[vout]`;
                            console.log(`[shell:executeFFmpeg] 🔊 通过 null 滤镜连接 [${lastLabel}] -> [vout]`);
                        } else {
                            // 无法提取标签，尝试直接添加 [vout]
                            modifiedVideoFilter = modifiedVideoFilter + '[vout]';
                            console.log(`[shell:executeFFmpeg] 🔊 无法提取最后标签，直接添加 [vout]`);
                        }
                    }

                    // 将音频混音滤镜添加到末尾
                    finalFilterContent = modifiedVideoFilter + ';' + audioMixConfig.mixFilter;
                    useAudioMix = true;

                    console.log(`[shell:executeFFmpeg] 🔊 组合滤镜长度: ${finalFilterContent.length}`);
                }

                const tempDir = os.tmpdir();
                const filterScriptPath = path.join(tempDir, `ffmpeg_filter_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.txt`);

                console.log(`[shell:executeFFmpeg] 将filter_complex写入文件: ${filterScriptPath}`);
                await fs.writeFile(filterScriptPath, finalFilterContent, 'utf-8');

                // 🆕 根据是否有音效混音，构建不同的参数
                let args: string[];
                if (useAudioMix) {
                    // 有音效时：添加音效输入，映射视频和音频输出
                    // 使用新语法 -/filter_complex 而不是已弃用的 -filter_complex_script
                    args = [
                        '-y',
                        '-i', normalizedInputVideo,  // 🔧 使用转换后的路径
                        ...(data.stickerInputs || []), // 🆕 添加贴纸输入
                        ...audioInputArgs,  // 音效文件输入（已转换）
                        '-/filter_complex', filterScriptPath,
                        '-map', '[vout]',
                        '-map', '[aout]',
                        '-c:v', 'libx264',
                        '-preset', 'medium',
                        '-crf', '18',
                        '-c:a', 'aac',  // 需要重新编码音频
                        '-b:a', '192k',
                        normalizedOutputVideo  // 🔧 使用转换后的路径
                    ];
                    console.log(`[shell:executeFFmpeg] 🔊 使用音效混音模式执行 FFmpeg`);
                } else {
                    // 无音效时：原始逻辑
                    // 注意：新版 FFmpeg 使用 -/filter_complex 参数从文件读取
                    args = [
                        '-y',
                        '-i', normalizedInputVideo,  // 🔧 使用转换后的路径
                        ...(data.stickerInputs || []), // 🆕 添加贴纸输入
                        '-/filter_complex', filterScriptPath,
                        '-c:v', 'libx264',
                        '-preset', 'medium',
                        '-crf', '18',
                        '-c:a', 'copy',
                        normalizedOutputVideo  // 🔧 使用转换后的路径
                    ];
                }

                try {
                    const result = await shellApi.execFFmpegCommand(args, { cwd: ffmpegCwd });
                    try { await fs.unlink(filterScriptPath); } catch (e) {}
                    return result;
                } catch (error: any) {
                    const exitCode = error?.message ? parseInt(error.message.match(/code\s+(\d+)/)?.[1] || '0') : 0;
                    if (exitCode !== 0) {
                        Log.warn("shell:executeFFmpeg.filterFileMode.failed", {
                            exitCode,
                            trying: "filter_complex_script fallback"
                        });
                        try {
                            const fallbackArgs = args.map(a => a === '-/filter_complex' ? '-filter_complex_script' : a);
                            const result2 = await shellApi.execFFmpegCommand(fallbackArgs, { cwd: ffmpegCwd });
                            try { await fs.unlink(filterScriptPath); } catch (e) {}
                            return result2;
                        } catch (error2: any) {
                            Log.warn("shell:executeFFmpeg.filter_complex_script.failed", {
                                error: error2?.message?.substring(0, 200),
                                trying: "inline filter_complex fallback"
                            });
                            try {
                                const inlineArgs = args
                                    .filter(a => a !== '-/filter_complex' && a !== '-filter_complex_script' && a !== filterScriptPath)
                                ;
                                const inlineIdx = inlineArgs.indexOf('-y') >= 0 ? 1 : 0;
                                inlineArgs.splice(inlineIdx, 0, '-filter_complex', finalFilterContent);
                                const result3 = await shellApi.execFFmpegCommand(inlineArgs, { cwd: ffmpegCwd });
                                try { await fs.unlink(filterScriptPath); } catch (e) {}
                                return result3;
                            } catch (error3) {
                                try { await fs.unlink(filterScriptPath); } catch (e) {}
                                throw error3;
                            }
                        }
                    }
                    try { await fs.unlink(filterScriptPath); } catch (e) {}
                    throw error;
                }
            }
        }

        // 普通命令模式：解析命令字符串为参数数组
        const args = parseFFmpegCommand(commandOrJson);

        Log.info("shell:executeFFmpeg.normalCommand", {
            argsCount: args.length,
            command: commandOrJson.substring(0, 200) + '...'
        });

        return await shellApi.execFFmpegCommand(args);

    } catch (error: any) {
        Log.error("shell:executeFFmpeg.error", {
            error: error?.message || String(error),
            command: commandOrJson.substring(0, 200) + '...'
        });
        throw error;
    }
});

console.log("[shell/main.ts] IPC handlers registered!");

/**
 * 解析FFmpeg命令字符串为参数数组
 */
function parseFFmpegCommand(command: string): string[] {
    const args: string[] = [];
    let current = '';
    let inQuote = false;
    let quoteChar = '';

    const cmdStr = command.startsWith('ffmpeg ') ? command.substring(7) : command;

    for (let i = 0; i < cmdStr.length; i++) {
        const char = cmdStr[i];

        if ((char === '"' || char === "'") && !inQuote) {
            inQuote = true;
            quoteChar = char;
        } else if (char === quoteChar && inQuote) {
            inQuote = false;
            quoteChar = '';
        } else if (char === ' ' && !inQuote) {
            if (current.length > 0) {
                args.push(current);
                current = '';
            }
        } else {
            current += char;
        }
    }

    if (current.length > 0) {
        args.push(current);
    }

    return args;
}

export const shell = {
    execFFmpegCommand: shellApi.execFFmpegCommand,
    extractAudioFromVideo: shellApi.extractAudioFromVideo,
    getPythonPath: shellApi.getPythonPath,
    showItemInFolder: shellApi.showItemInFolder,
};

export default shell;
