import { json, type RequestHandler } from '@sveltejs/kit';

import * as fs from 'fs/promises';
import * as path from 'path';
import { exec } from 'child_process';
import * as util from 'util';

import { createCanvas, loadImage } from 'canvas';

const execPromise = util.promisify(exec);

const detectCropAreaOnServer = async (inputPath: string): Promise<string> => {
	// --- START: 수정된 부분 (다중 프레임 처리) ---
	const tempFrameDir = path.join(process.cwd(), 'tmp', `frames-${Date.now()}`);

	try {
		// 1. 임시 프레임 폴더 생성
		await fs.mkdir(tempFrameDir, { recursive: true });

		// 2. ffprobe로 동영상 총 길이를 가져옵니다.
		const ffprobeOutput = await execPromise(
			`ffprobe -v error -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 ${inputPath}`
		);
		const duration = parseFloat(ffprobeOutput.stdout);
		const startTimeForFrames = duration > 10 ? duration / 2 : 1; // 영상 중간 또는 1초 지점

		// 3. 영상 중간부터 30개의 프레임을 png 파일들로 추출합니다.
		await execPromise(
			`ffmpeg -ss ${startTimeForFrames} -i ${inputPath} -vframes 30 -q:v 2 -y ${path.join(
				tempFrameDir,
				'frame_%03d.png'
			)}`
		);

		const frameFiles = await fs.readdir(tempFrameDir);
		const allBounds: { x1: number; y1: number; x2: number; y2: number }[] = [];

		// 4. 추출된 각 프레임을 분석합니다.
		for (const frameFile of frameFiles) {
			const framePath = path.join(tempFrameDir, frameFile);
			const img = await loadImage(framePath);
			const canvas = createCanvas(img.width, img.height);
			const ctx = canvas.getContext('2d');
			const { width: canvasWidth, height: canvasHeight } = canvas;

			ctx.drawImage(img, 0, 0, img.width, img.height);

			const imageDataObj = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
			const imageData = imageDataObj.data;

			const blackoutAreas = [
				{ x: 0, y: 0, width: 154, height: 94 },
				{ x: 1766, y: 0, width: 154, height: 94 },
				{ x: 0, y: 995, width: 1920, height: 85 }
			];

			for (const area of blackoutAreas) {
				for (let y = area.y; y < area.y + area.height; y++) {
					if (y >= canvasHeight) continue;
					for (let x = area.x; x < area.x + area.width; x++) {
						if (x >= canvasWidth) continue;
						const i = (y * canvasWidth + x) * 4;
						imageData[i] = 0;
						imageData[i + 1] = 0;
						imageData[i + 2] = 0;
					}
				}
			}

			const verticalProfile = new Array(canvasHeight).fill(0);
			const horizontalProfile = new Array(canvasWidth).fill(0);

			for (let y = 0; y < canvasHeight; y++) {
				for (let x = 0; x < canvasWidth; x++) {
					const i = (y * canvasWidth + x) * 4;
					const brightness = (imageData[i] + imageData[i + 1] + imageData[i + 2]) / 3;
					verticalProfile[y] += brightness;
					horizontalProfile[x] += brightness;
				}
			}

			const totalVerticalBrightness = verticalProfile.reduce((sum, val) => sum + val, 0);
			const avgVerticalBrightness = totalVerticalBrightness / canvasHeight;
			const verticalThreshold = avgVerticalBrightness * 0.15;

			const totalHorizontalBrightness = horizontalProfile.reduce((sum, val) => sum + val, 0);
			const avgHorizontalBrightness = totalHorizontalBrightness / canvasWidth;
			const horizontalThreshold = avgHorizontalBrightness * 0.15;

			let y1 = 0, y2 = canvasHeight - 1, x1 = 0, x2 = canvasWidth - 1;

			for (let i = 0; i < canvasHeight; i++) { if (verticalProfile[i] > verticalThreshold) { y1 = i; break; } }
			for (let i = canvasHeight - 1; i >= 0; i--) { if (verticalProfile[i] > verticalThreshold) { y2 = i; break; } }
			for (let i = 0; i < canvasWidth; i++) { if (horizontalProfile[i] > horizontalThreshold) { x1 = i; break; } }
			for (let i = canvasWidth - 1; i >= 0; i--) { if (horizontalProfile[i] > horizontalThreshold) { x2 = i; break; } }

			if (x2 > x1 && y2 > y1) {
				allBounds.push({ x1, y1, x2, y2 });
			}
		}

		if (allBounds.length === 0) return '';

		// 5. 모든 프레임의 경계값들 중에서 가장 안쪽 영역(안전 영역)을 찾습니다.
		const finalX1 = Math.max(...allBounds.map((b) => b.x1));
		const finalY1 = Math.max(...allBounds.map((b) => b.y1));
		const finalX2 = Math.min(...allBounds.map((b) => b.x2));
		const finalY2 = Math.min(...allBounds.map((b) => b.y2));

		const width = finalX2 - finalX1 + 1;
		const height = finalY2 - finalY1 + 1;

		if (width <= 0 || height <= 0) return '';

		const cropParams = `${width}:${height}:${finalX1}:${finalY1}`;
		console.log(`서버(다중 프레임)에서 찾은 최종 Crop 영역: ${cropParams}`);
		return cropParams;
		// --- END: 수정된 부분 ---
	} catch (error) {
		console.error('node-canvas 픽셀 처리 중 오류:', error);
		throw new Error('Image processing with node-canvas failed');
	} finally {
		// 6. 임시 프레임 폴더와 그 안의 모든 파일을 삭제합니다.
		await fs.rm(tempFrameDir, { recursive: true, force: true });
	}
};

// --- API 요청 핸들러 (이하 동일) ---
export const POST: RequestHandler = async ({ request }) => {
	const data = await request.json();
	const { action, segments } = data;

	const inputPath = path.join(process.cwd(), 'tmp', 'process.mp4');

	try {
		if (action === 'detect-crop') {
			const cropParams = await detectCropAreaOnServer(inputPath);
			return json({ success: true, cropParams });
		}

		if (action === 'crop-full-video') {
			const { cropParams } = data;

			if (!cropParams || !/^\d+:\d+:\d+:\d+$/.test(cropParams)) {
				return json({ success: false, error: '잘못된 Crop 파라미터입니다.' }, { status: 400 });
			}

			const tempOutputPath = path.join(process.cwd(), 'tmp', `process_crop_${Date.now()}.mp4`);

			try {
				const command = `ffmpeg -i ${inputPath} -vf "crop=${cropParams}" -qp 10 -c:v h264_nvenc -c:a copy -y ${tempOutputPath}`;

				console.log('실행할 FFmpeg Crop 명령어:', command);
				await execPromise(command);

				// ▼▼▼ 아래 로그가 터미널에 출력되는지 확인하세요. ▼▼▼
    			console.log('✅ FFmpeg Crop 작업 성공! 이제 파일을 교체합니다.'); 

				// 원본 파일을 Crop된 파일로 교체
				await fs.rename(tempOutputPath, inputPath);
				console.log(`파일 교체 완료: ${tempOutputPath} -> ${inputPath}`);

				// 교체된 새 비디오 파일을 클라이언트로 전송하여 미리보기 업데이트
				/*
				const videoBuffer = await fs.readFile(inputPath);
				return new Response(videoBuffer, {
					status: 200,
					headers: { 'Content-Type': 'video/mp4' }
				});
				*/
				return json({ success: true, message: 'Crop 작업이 성공적으로 완료되었습니다.' });

			} catch (error) {
				console.error('전체 비디오 Crop 처리 중 오류:', error);
				await fs.rm(tempOutputPath, { force: true }).catch(() => {}); // 임시 파일 삭제
				return json({ success: false, error: '비디오 Crop 처리 중 오류가 발생했습니다.' }, { status: 500 });
			}
		}

		if (action === 'cut-segments') {
			const { cropParams } = data;
			const outputUrls: { id: number; url: string }[] = [];
			const outputDir = path.join(process.cwd(), 'static', 'cuts');
			await fs.mkdir(outputDir, { recursive: true });

			for (const segment of segments) {
				const outputFileName = `cut-${segment.id}-${Date.now()}.mp4`;
				const outputPath = path.join(outputDir, outputFileName);
				const duration = segment.end - segment.start;

				const vfOption = cropParams ? `-vf "crop=${cropParams}"` : '';

				const command = `ffmpeg -ss ${segment.start} -t ${duration} -i ${inputPath} ${vfOption} -c:v h264_nvenc -c:a copy -y ${outputPath}`;

				console.log('실행할 FFmpeg 명령어:', command);
				await execPromise(command);

				outputUrls.push({ id: segment.id, url: `/cuts/${outputFileName}` });
			}
			return json({ success: true, outputUrls });
		}

		return json({ success: false, error: '알 수 없는 작업입니다.' }, { status: 400 });
	} catch (error) {
		console.error('서버 처리 중 오류:', error);
		return json({ success: false, error: '서버 처리 중 오류가 발생했습니다.' }, { status: 500 });
	}
};

