<script lang="ts">
	import { onMount } from 'svelte';
	import { FFmpeg } from '@ffmpeg/ffmpeg';
	import { fetchFile, toBlobURL } from '@ffmpeg/util';
	import type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types';

	// --- 상태 변수 선언 ---
	let ffmpeg: FFmpeg | null = null;
	let videoURL: string = '';
	let videoElement: HTMLVideoElement;
	let originalFileName: string = '';
	let message: string = 'FFmpeg를 로드하려면 클릭하세요.';
	let startTime: number = 0;
	let endTime: number = 0;
	let isLoading: boolean = false;

	let detectedCropParams: string = ''; // 계산된 Crop 파라미터를 저장할 변수
	let cropInfo: string = ''; // 계산된 Crop 정보를 표시할 변수
	let isDetectingCrop: boolean = false; // Crop 계산 중 상태를 추적할 변수

	let isUploadingOriginal: boolean = false;
	let uploadProgress: number = 0; // 0에서 100 사이의 업로드 진행률

	// --- 다중 구간 편집을 위한 타입 및 상태 변수 ---
	interface TimeSegment {
		id: number;
		start: number;
		end: number;
		resultURL?: string;
		isUploading?: boolean;
		uploadStatus?: 'success' | 'error';
	}

	let segments: TimeSegment[] = [];
	let nextSegmentId = 0;

	// --- 반응형 변수 ---
	$: allProcessed = segments.length > 0 && segments.every((s) => s.resultURL);

	// --- 핵심 기능 함수 ---

	const loadFFmpeg = async () => {
		if (isLoading || ffmpeg) return;
		isLoading = true;
		message = 'FFmpeg core 로딩 중...';

		try {
			ffmpeg = new FFmpeg();
			ffmpeg.on('log', ({ message }: LogEvent) => {
				// console.log(message); // 디버깅 시에만 활성화
			});

			const baseURL = '/';
			await ffmpeg.load({
				coreURL: await toBlobURL(`${baseURL}ffmpeg-core.js`, 'text/javascript'),
				wasmURL: await toBlobURL(`${baseURL}ffmpeg-core.wasm`, 'application/wasm')
			});

			ffmpeg = ffmpeg; // Svelte 반응성 트리거
			message = 'FFmpeg 로드 완료! 동영상을 선택하세요.';
		} catch (err) {
			console.error(err);
			message = 'FFmpeg 로드 실패. 인터넷 연결을 확인하거나 브라우저를 새로고침하세요.';
		} finally {
			isLoading = false;
		}
	};

	const handleFileSelect = async (e: Event) => {
		const target = e.target as HTMLInputElement;
		const file = target.files?.[0];

		if (file && ffmpeg) {
			// 새 영상이므로 기존 상태 초기화
			videoURL = URL.createObjectURL(file);
			originalFileName = file.name;
			startTime = 0;
			endTime = 0;
			segments = [];

			detectedCropParams = '';	 // Crop 파라미터 초기화
			cropInfo = ''; // Crop 정보 초기화
			isDetectingCrop = true; // Crop 계산 시작 상태로 변경

			await uploadOriginalVideo(file);

			try {
				// FFmpeg 메모리 파일 시스템에 파일 쓰기
				await ffmpeg.writeFile(file.name, await fetchFile(file));
				// Crop 영역 계산 함수 호출
				const cropParams = await detectCropAreaProgrammatically(file.name);

				detectedCropParams = cropParams; // ✅ 계산 결과를 전용 변수에 저장!

				if (cropParams) {
					const [width, height, x, y] = cropParams.split(':');
					cropInfo = `시작점: (${x}, ${y}), 크기: (${width} x ${height})`;
				} else {
					cropInfo = '자동 Crop 영역을 찾지 못했습니다.';
				}
			} catch (error) {
				console.error('Crop 영역 계산 실패:', error);
				cropInfo = 'Crop 영역 계산 중 오류가 발생했습니다.';
			} finally {
				isDetectingCrop = false; // Crop 계산 종료 상태로 변경
			}
		}
	};

	const setStartTime = () => {
		if (videoElement) startTime = videoElement.currentTime;
	};

	const setEndTime = () => {
		if (videoElement) endTime = videoElement.currentTime;
	};

	const addSegment = () => {
		if (startTime >= endTime) {
			alert('시작 시간은 종료 시간보다 빨라야 합니다.');
			return;
		}
		segments = [...segments, { id: nextSegmentId++, start: startTime, end: endTime }];
	};

	const removeSegment = (id: number) => {
		segments = segments.filter((segment) => segment.id !== id);
	};

	const previewSegment = (segment: TimeSegment) => {
		if (videoElement) {
			videoElement.currentTime = segment.start;
			videoElement.play();

			const stopAtEnd = () => {
				if (videoElement.currentTime >= segment.end) {
					videoElement.pause();
					videoElement.removeEventListener('timeupdate', stopAtEnd);
				}
			};
			videoElement.addEventListener('timeupdate', stopAtEnd);
		}
	};

	const detectCropAreaProgrammatically = async (inputFileName: string): Promise<string> => {
		message = '최적의 Crop 영역을 계산하는 중...';
		const tempFramePath = 'temp-frame.png';
		await ffmpeg.exec([
			'-ss', '5',
			'-i', inputFileName,
			'-vframes', '1',
			'-q:v', '2',
			tempFramePath
		]);

		const frameData = await ffmpeg.readFile(tempFramePath);
		const blob = new Blob([frameData], { type: 'image/png' });
		const url = URL.createObjectURL(blob);

		try {
			const img = await new Promise<HTMLImageElement>((resolve, reject) => {
				const image = new Image();
				image.onload = () => resolve(image);
				image.onerror = reject;
				image.src = url;
			});

			const canvas = document.createElement('canvas');
			const ctx = canvas.getContext('2d', { willReadFrequently: true });
			if (!ctx) return '';

			canvas.width = img.naturalWidth;
			canvas.height = img.naturalHeight;
			ctx.drawImage(img, 0, 0);

			// ### START: 추가된 부분 - 오버레이 영역 검게 칠하기 ###

			// GIMP에서 확인한 좌표를 기반으로 정보 오버레이 영역을 정의합니다.
			// 참고: 이 좌표는 1920x1080 해상도에만 유효할 수 있습니다.
			const blackoutAreas = [
				{ x: 0, y: 0, width: 154, height: 94 },     // 좌상단 "Live" 텍스트
				{ x: 1766, y: 0, width: 154, height: 94 },  // 우상단 "1.00x" 텍스트
				{ x: 0, y: 995, width: 1920, height: 85 }  // 하단 정보 바
			];

			// 해당 영역들을 검은색 사각형으로 덮어씁니다.
			ctx.fillStyle = 'black';
			for (const area of blackoutAreas) {
				ctx.fillRect(area.x, area.y, area.width, area.height);
			}

			// ### END: 추가된 부분 ###

			// 수정된 캔버스에서 이미지 데이터를 다시 읽어옵니다.
			const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;

			const verticalProfile = new Array(canvas.height).fill(0);
			const horizontalProfile = new Array(canvas.width).fill(0);

			for (let y = 0; y < canvas.height; y++) {
				for (let x = 0; x < canvas.width; x++) {
					const i = (y * canvas.width + 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 / canvas.height;
			const verticalThreshold = avgVerticalBrightness * 0.1;

			const totalHorizontalBrightness = horizontalProfile.reduce((sum, val) => sum + val, 0);
			const avgHorizontalBrightness = totalHorizontalBrightness / canvas.width;
			const horizontalThreshold = avgHorizontalBrightness * 0.1;

			let y1 = 0, y2 = canvas.height - 1, x1 = 0, x2 = canvas.width - 1;

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

			const width = x2 - x1 + 1;
			const height = y2 - y1 + 1;

			if (width <= 0 || height <= 0) return '';
			
			const cropParams = `${width}:${height}:${x1}:${y1}`;
			console.log(`프로그래밍 방식으로 찾은 Crop 영역: ${cropParams}`);
			return cropParams;
		} catch (error) {
			console.error('Crop 영역 계산 중 오류:', error);
			return '';
		} finally {
			URL.revokeObjectURL(url);
		}
	};

	const cutAllSegments = async () => {
		if (!ffmpeg || !ffmpeg.loaded) { message = 'FFmpeg를 로드해주세요.'; return; }
		if (segments.length === 0) { message = '먼저 구간을 추가해주세요.'; return; }
		
		isLoading = true;
		
		const inputFileName = 'input.mp4';
		await ffmpeg.writeFile(inputFileName, await fetchFile(videoURL));

		//const cropParams = await detectCropAreaProgrammatically(inputFileName);

		for (let i = 0; i < segments.length; i++) {
			const segment = segments[i];
            const outputFileName = `output-${segment.id}.mp4`;
            message = `${segments.length}개 중 ${i + 1}번째 구간 처리 중 (재인코딩으로 인해 시간이 걸릴 수 있습니다)...`;

            const duration = segment.end - segment.start;

            // ✅ -ss와 -t를 -i 앞으로 옮겨서 입력 파일 자체를 필요한 부분만 읽도록 최적화합니다.
            const command = [
                '-ss', `${segment.start}`,
                '-t', `${duration}`,
                '-i', inputFileName,
            ];

			// crop 파라미터를 찾았을 경우에만 crop 필터 추가
			if (detectedCropParams) {
				command.push('-vf', `crop=${detectedCropParams}`);
			}
            
            // 오디오는 그대로 복사하고, 비디오는 기본 설정으로 재인코딩
            command.push('-c:a', 'copy', outputFileName);

            await ffmpeg.exec(command);

			const data = await ffmpeg.readFile(outputFileName);
			const url = URL.createObjectURL(new Blob([(data as Uint8Array).buffer], { type: 'video/mp4' }));
			segments = segments.map(s => s.id === segment.id ? { ...s, resultURL: url } : s);
		}
		message = '모든 구간 처리 완료!';
		isLoading = false;
	};

	const uploadSegment = async (segment: TimeSegment) => {
		if (!segment.resultURL) return;
		segments = segments.map(s => s.id === segment.id ? { ...s, isUploading: true } : s);
		
		try {
			const response = await fetch(segment.resultURL);
			const blob = await response.blob();
			const baseName = originalFileName.split('.').slice(0, -1).join('.') || originalFileName;
			const fileName = `${baseName}_cut-${segment.id}-${segment.start.toFixed(0)}s-${segment.end.toFixed(0)}s.mp4`;
			
			const formData = new FormData();
			formData.append('video', blob);
			formData.append('fileName', fileName);

			const uploadResponse = await fetch('/api/upload', { method: 'POST', body: formData });
			if (!uploadResponse.ok) throw new Error('서버 업로드 실패');
			
			segments = segments.map(s => s.id === segment.id ? { ...s, isUploading: false, uploadStatus: 'success' } : s);
		} catch (err) {
			console.error('업로드 실패:', err);
			segments = segments.map(s => s.id === segment.id ? { ...s, isUploading: false, uploadStatus: 'error' } : s);
		}
	};
    
	const uploadAllSegments = async () => {
		if (!allProcessed) return;
		message = '전체 업로드를 시작합니다...';
		isLoading = true;
		for (const segment of segments) {
			if (segment.resultURL && segment.uploadStatus !== 'success') {
				await uploadSegment(segment);
			}
		}
		isLoading = false;
		message = '전체 업로드 요청이 완료되었습니다.';
	};

	const downloadAllSegments = async () => {
        if (!allProcessed) return;
        message = '개별 파일 다운로드를 시작합니다...';
        isLoading = true;
        try {
            const processedSegments = segments.filter(s => s.resultURL);
            for (const segment of processedSegments) {
				const link = document.createElement('a');
				link.href = segment.resultURL!;
				const baseName = originalFileName.split('.').slice(0, -1).join('.') || originalFileName;
				const fileName = `${baseName}_cut-${segment.id}-${segment.start.toFixed(0)}s-${segment.end.toFixed(0)}s.mp4`;
				link.download = fileName;
				document.body.appendChild(link);
				link.click();
				document.body.removeChild(link);
				setTimeout(() => URL.revokeObjectURL(link.href), 100);
				await new Promise(resolve => setTimeout(resolve, 300));
            }
            message = `${processedSegments.length}개 파일의 다운로드를 요청했습니다.`;
        } catch (error) {
            console.error('개별 파일 다운로드 오류:', error);
            message = '파일 다운로드 중 오류가 발생했습니다.';
        } finally {
            isLoading = false;
        }
    };

	
	const uploadOriginalVideo = async (file: File): Promise<void> => {
		return new Promise((resolve, reject) => {
			isUploadingOriginal = true;
			uploadProgress = 0;
			message = '원본 동영상을 서버로 업로드하는 중...';

			const formData = new FormData();
			formData.append('video', file);

			const xhr = new XMLHttpRequest();

			// 업로드 진행률 업데이트
			xhr.upload.onprogress = (event) => {
				if (event.lengthComputable) {
					const percentComplete = (event.loaded / event.total) * 100;
					uploadProgress = percentComplete;
				}
			};

			// 업로드 성공 시
			xhr.onload = () => {
				if (xhr.status >= 200 && xhr.status < 300) {
					console.log('원본 파일 업로드 결과:', xhr.responseText);
					message = '원본 파일 업로드 완료! Crop 영역을 계산합니다.';
					isUploadingOriginal = false;
					resolve();
				} else {
					// 서버에서 에러 응답 시
					console.error('원본 파일 업로드 실패:', xhr.statusText);
					message = '원본 파일 업로드 중 오류가 발생했습니다.';
					isUploadingOriginal = false;
					reject(new Error(xhr.statusText));
				}
			};

			// 업로드 중 네트워크 에러 등 발생 시
			xhr.onerror = () => {
				console.error('원본 파일 업로드 실패: 네트워크 오류');
				message = '원본 파일 업로드 중 네트워크 오류가 발생했습니다.';
				isUploadingOriginal = false;
				reject(new Error('네트워크 오류'));
			};

			xhr.open('POST', '/api/upload-original', true);
			xhr.send(formData);
		});
	};
	
</script>

<main class="mx-auto max-w-screen-2xl p-4 sm:p-6 lg:p-8">
	<div class="text-center mb-8">
		<h1 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
			🎬 내시경 BigData 동영상 편집기
		</h1>
	</div>

	{#if !ffmpeg?.loaded}
		<div class="text-center">
			<button
				on:click={loadFFmpeg}
				disabled={isLoading}
				class="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-6 py-3 text-base font-medium text-white shadow-sm hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed"
			>
				{message}
			</button>
		</div>
	{:else}
		<p class="p-4 mb-6 bg-blue-50 text-blue-700 border border-blue-200 rounded-lg text-center">
			{message}
		</p>

		<div class="flex flex-col lg:flex-row gap-6 items-start">
			{#if videoURL}
				<div class="w-full lg:w-1/2">
					<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl">
						<div class="p-6">
							<h2 class="text-xl font-semibold text-gray-800 mb-4">동영상 재생</h2>
                            <video src={videoURL} bind:this={videoElement} class="w-full rounded-lg" controls>
                                <track kind="captions" src="data:text/vtt,WEBVTT%0A%0A" srclang="ko" label="Korean captions" default />
                            </video>
						</div>
					</section>
				</div>
			{/if}

			<div class="w-full lg:w-1/4 flex flex-col gap-6">
				<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6">
					<h2 class="text-xl font-semibold text-gray-800 mb-4">1. 동영상 파일 선택</h2>
					<label
						class="w-full text-center cursor-pointer rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50"
					>
						동영상 파일 불러오기
						<input type="file" accept="video/*" on:change={handleFileSelect} class="sr-only" />
					</label>

					<div class="mt-4 space-y-1 text-sm">
						{#if isUploadingOriginal}
							<div>
								<p class="font-medium text-gray-900 mb-1">서버로 업로드 중...</p>
								<progress class="w-full" max="100" value={uploadProgress}></progress>
								<p class="text-right font-mono text-gray-700">{uploadProgress.toFixed(0)}%</p>
							</div>
						{/if}
						
						{#if isDetectingCrop}
							<p class="text-gray-500 animate-pulse">자동 Crop 영역 계산 중...</p>
						{:else if cropInfo}
							<div>
								<p><strong class="font-medium text-gray-900">자동 Crop 영역:</strong></p>
								<p class="text-gray-700 font-mono bg-gray-50 p-2 rounded">{cropInfo}</p>
							</div>
						{/if}
					</div>
				</section>

				{#if videoURL}
					<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6">
						<h3 class="text-lg font-semibold text-gray-800 mb-4">2. 구간 추가</h3>
						<div class="flex gap-2 mb-4">
							<button on:click={setStartTime} class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50">시작 시간 설정</button>
							<button on:click={setEndTime} class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50">종료 시간 설정</button>
						</div>
						<div class="space-y-1 text-sm mb-4">
							<p><strong class="font-medium text-gray-900">시작:</strong> {startTime.toFixed(2)}초</p>
							<p><strong class="font-medium text-gray-900">종료:</strong> {endTime.toFixed(2)}초</p>
						</div>
						<button on:click={addSegment} class="w-full rounded-md border border-transparent bg-green-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-green-700">
							➕ 구간 추가하기
						</button>
					</section>
				{/if}
			</div>

			{#if videoURL}
				<div class="w-full lg:w-1/4">
					<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6 flex flex-col h-[calc(100vh-15rem)]">
						<h2 class="text-xl font-semibold text-gray-800 mb-4">3. 자르기 목록 ({segments.length}개)</h2>
						<div class="space-y-4 mb-6 flex-1 overflow-y-auto pr-2">
							{#each segments as segment (segment.id)}
                                <div
                                    role="button"
                                    tabindex="0"
                                    on:click={() => previewSegment(segment)}
                                    on:keydown={(e) => { if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); previewSegment(segment); } }}
                                    class="p-3 border rounded-lg flex items-center justify-between transition-all cursor-pointer hover:bg-gray-100"
                                    class:bg-green-50={segment.resultURL}
                                    class:border-blue-300={segment.isUploading}
                                    class:border-green-400={segment.uploadStatus === 'success'}
                                    class:border-red-400={segment.uploadStatus === 'error'}
                                >
                                    <div class="flex-1 overflow-hidden">
                                        <p class="font-medium text-gray-800 truncate">{segment.start.toFixed(2)}초 ~ {segment.end.toFixed(2)}초</p>
                                        {#if segment.resultURL}
                                            <div class="flex items-center gap-2 mt-1">
                                                <a 
                                                    href={segment.resultURL} 
                                                    download={`${originalFileName.split('.').slice(0, -1).join('.')}_cut-${segment.id}-${segment.start.toFixed(0)}s-${segment.end.toFixed(0)}s.mp4`} 
                                                    class="text-sm text-indigo-600 hover:underline"
                                                >다운로드</a>
                                                
                                                <button 
                                                    on:click|stopPropagation={() => uploadSegment(segment)} 
                                                    disabled={segment.isUploading || segment.uploadStatus === 'success'}
                                                    class="text-xs px-2 py-1 rounded bg-blue-500 text-white hover:bg-blue-600 disabled:bg-gray-400"
                                                >
                                                    {#if segment.isUploading}
                                                        업로드 중...
                                                    {:else if segment.uploadStatus === 'success'}
                                                        업로드 완료 ✅
                                                    {:else}
                                                        업로드
                                                    {/if}
                                                </button>
                                                {#if segment.uploadStatus === 'error'}
                                                    <span class="text-xs text-red-500">실패</span>
                                                {/if}
                                            </div>
                                        {/if}
                                    </div>
                                    <button on:click|stopPropagation={() => removeSegment(segment.id)} class="text-red-500 hover:text-red-700 font-bold px-2 ml-2">X</button>
                                </div>
							{:else}
								<p class="text-gray-500 text-center py-4">추가된 구간이 없습니다.</p>
							{/each}
						</div>
						<div class="mt-auto grid grid-cols-1 md:grid-cols-3 gap-2">
							<button on:click={cutAllSegments} disabled={isLoading || segments.length === 0} class="w-full rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 disabled:opacity-50">
								✂️ 전체 잘라내기
							</button>
							<button on:click={downloadAllSegments} disabled={isLoading || !allProcessed} class="w-full rounded-md border border-transparent bg-green-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-green-700 disabled:opacity-50 disabled:bg-gray-400">
								📦 전체 다운로드
							</button>
							<button 
								on:click={uploadAllSegments}
								disabled={isLoading || !allProcessed}
								class="w-full rounded-md border border-transparent bg-purple-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-purple-700 disabled:opacity-50 disabled:bg-gray-400"
							>
								🚀 전체 업로드
							</button>
						</div>
					</section>
				</div>
			{/if}
		</div>
	{/if}
</main>