import { type RequestHandler } from '@sveltejs/kit';
import * as path from 'path';
import { spawn } from 'child_process';
import * as fs from 'fs';
import * as util from 'util';
import { exec } from 'child_process';
import { activeProcesses } from '$lib/server/processes';

const execPromise = util.promisify(exec);

// ----------------------
// 🔸 비디오 길이 가져오기
// ----------------------
const getVideoDuration = async (filePath: string): Promise<number> => {
    try {
        const { stdout } = await execPromise(
            `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${filePath}"`
        );
        return parseFloat(stdout);
    } catch (error) {
        console.error('Error getting video duration:', error);
        return 0;
    }
};

// ----------------------
// 🔸 Node 종료 시 FFmpeg 정리
// ----------------------
process.on('exit', () => {
    console.log('🧹 Cleaning up leftover FFmpeg processes...');
    for (const [id, proc] of activeProcesses.entries()) {
        try {
            proc.kill('SIGKILL');
        } catch {}
    }
});

// ----------------------
// 🔸 (선택) 좀비 모니터링
// ----------------------
setInterval(() => {
    exec('ps -eo pid,ppid,stat,comm | grep ffmpeg | grep Z', (err, stdout) => {
        if (stdout.trim()) {
            console.warn('⚠️ Found zombie ffmpeg processes:\n', stdout);
        }
    });
}, 60000); // 1분마다 체크

// ----------------------
// 🔸 GET Handler
// ----------------------
export const GET: RequestHandler = ({ request }) => {
    const url = new URL(request.url);
    const cropParams = url.searchParams.get('crop');

    if (!cropParams || !/^\d+:\d+:\d+:\d+$/.test(cropParams)) {
        return new Response('Invalid crop parameters', { status: 400 });
    }

    const inputStream = new ReadableStream({
        async start(controller) {
            const processId = `crop-${Date.now()}`;
            const inputPath = path.join(process.cwd(), 'tmp', 'process.mp4');
            const tempOutputPath = path.join(process.cwd(), 'tmp', `process_crop_${Date.now()}.mp4`);
            let isStreamClosed = false;

            // 안전한 enqueue 함수
            const safeEnqueue = (data: string) => {
                try {
                    if (!isStreamClosed) controller.enqueue(data);
                } catch {
                    console.warn('⚠️ Attempted to enqueue after close. Ignoring.');
                }
            };

            // 안전한 close 함수
            const safeClose = () => {
                if (!isStreamClosed) {
                    isStreamClosed = true;
                    try {
                        controller.close();
                    } catch {
                        console.warn('⚠️ Attempted to close an already closed stream. Ignoring.');
                    }
                }
            };

            const totalDuration = await getVideoDuration(inputPath);
            if (totalDuration === 0) {
                safeEnqueue('data: {"error": "Failed to get video duration."}\n\n');
                safeClose();
                return;
            }

            const ffmpegArgs = [
                '-i', inputPath,
                '-vf', `crop=${cropParams}`,
                '-qp', '10',
                '-c:v', 'h264_nvenc',
                '-c:a', 'copy',
                '-y', tempOutputPath,
                '-progress', 'pipe:1'
            ];

            console.log('🚀 Spawning FFmpeg with args:', ffmpegArgs.join(' '));
            const ffmpegProcess = spawn('ffmpeg', ffmpegArgs);
            ffmpegProcess.unref(); // ✅ Node 종료 시 좀비 방지

            activeProcesses.set(processId, ffmpegProcess);
            safeEnqueue(`data: ${JSON.stringify({ processId })}\n\n`);

            const sendProgress = (progress: number) => {
                safeEnqueue(`data: ${JSON.stringify({ progress })}\n\n`);
            };

            ffmpegProcess.stdout.on('data', (data) => {
                const output = data.toString();
                const timeMatch = output.match(/out_time_ms=(\d+)/);
                if (timeMatch) {
                    const currentTimeMs = parseInt(timeMatch[1], 10);
                    const currentTime = currentTimeMs / 1_000_000;
                    const progress = Math.round((currentTime / totalDuration) * 100);
                    sendProgress(progress);
                }
            });

            ffmpegProcess.stderr.on('data', (data) => {
                console.error(`ffmpeg stderr: ${data}`);
            });

            ffmpegProcess.on('close', async (code, signal) => {
                console.log(`[${processId}] FFmpeg process closed with code: ${code}, signal: ${signal}`);
                
                // 먼저 프로세스 리스트에서 제거하고 리스너를 정리합니다.
                activeProcesses.delete(processId);
                ffmpegProcess.removeAllListeners();

                if (code === 0) {
                    console.log('✅ FFmpeg Crop process completed successfully.');
                    try {
                        await fs.promises.rename(tempOutputPath, inputPath);
                        console.log(`✅ File renamed successfully: ${tempOutputPath} -> ${inputPath}`);
                        safeEnqueue(`data: ${JSON.stringify({ progress: 100, status: 'completed' })}\n\n`);
                    } catch (renameError) {
                         console.error(`❌ File rename failed:`, renameError);
                         safeEnqueue(`data: ${JSON.stringify({ error: 'Processing complete, but failed to save file.' })}\n\n`);
                    }
                } else {
                    const msg = ffmpegProcess.killed
                        ? 'Process was cancelled by user.'
                        : `FFmpeg failed (code ${code}, signal ${signal})`;
                    console.error(`[${processId}] ${msg}`);
                    // 실패 시 임시 파일 삭제
                    await fs.promises.rm(tempOutputPath, { force: true }).catch(() => {});
                    safeEnqueue(`data: ${JSON.stringify({ error: msg })}\n\n`);
                }

                // 모든 작업이 끝난 후 스트림을 닫습니다.
                safeClose();
            });

            ffmpegProcess.on('error', (err) => {
                if (isStreamClosed) return;
                console.error('❌ Failed to start FFmpeg process:', err);
                safeEnqueue(`data: ${JSON.stringify({ error: 'Failed to start FFmpeg.' })}\n\n`);
                safeClose();
            });
        }
    });

    return new Response(inputStream, {
        headers: {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
        }
    });
};
