<script lang="ts">
	import { onMount, tick } from 'svelte';
	import { path } from '$lib/utils';

	// --- Type Definitions ---
	interface Video {
		Index: number;
		LocationFile: string;
		original_path?: string;
		WorkerID?: number | null;
	}

	interface Worker {
		id: number;
		name: string;
	}

	// --- State Variables ---
	let originals: Video[] = [];
	let allCrops: Video[] = [];
	let allSegments: Video[] = [];
	let workers: Worker[] = [];

	let selectedOriginal: Video | null = null;
	let selectedCrop: Video | null = null;
	let videoURL: string = '';
	let selectedVideoForPlayer: Video | null = null;
	let isLoading: boolean = true;
	let message: string = 'Loading video list...';

	// Manages the loading state for an individual worker update
	let updatingWorkerIndex: number | null = null;

	// --- Reactive Statements ---
	$: filteredCrops = selectedOriginal
		? allCrops.filter((crop) => crop.original_path === selectedOriginal.LocationFile)
		: [];

	$: filteredSegments = selectedCrop
		? allSegments.filter((segment) => segment.original_path === selectedCrop.LocationFile)
		: [];

	/**
	 * Fetches the list of workers from the server.
	 */
	async function loadWorkers() {
		try {
			const response = await fetch('/api/workers');
			if (!response.ok) {
				throw new Error('Failed to load worker list');
			}
			workers = (await response.json()) as Worker[];
		} catch (err: any) {
			message = `Error loading workers: ${err.message}`;
			console.error(err);
		}
	}

	/**
	 * Fetches all video lists from the server.
	 */
	async function loadAllVideos() {
		isLoading = true;
		message = 'Reloading video list...';
		try {
			const response = await fetch('/api/video-lists');
			if (!response.ok) {
				throw new Error('Failed to fetch video lists from the server.');
			}
			const data = await response.json();
			originals = data.originals || [];
			allCrops = data.crops || [];
			allSegments = data.segments || [];
			message = 'Select a video from the list to manage.';
		} catch (err: any) {
			message = `Error: ${err.message}`;
			console.error(err);
		} finally {
			isLoading = false;
		}
	}

	// Load all necessary data when the component mounts.
	onMount(() => {
		Promise.all([loadAllVideos(), loadWorkers()]);
	});

	/**
	 * Plays the selected video in the player.
	 */
	function playVideo(video: Video) {
		selectedVideoForPlayer = video;
		videoURL = `/api/video-stream/${video.Index}?t=${Date.now()}`; // Cache busting
	}

	/**
	 * Handles selection of an original video.
	 */
	function handleOriginalSelect(video: Video) {
		selectedOriginal = video;
		selectedCrop = null; // Reset child selection
		playVideo(video);
	}

	/**
	 * Handles selection of a cropped video.
	 */
	function handleCropSelect(video: Video) {
		selectedCrop = video;
		playVideo(video);
	}

	/**
	 * Handles changing the assigned worker for a video segment.
	 */
	async function handleWorkerChange(video, event) {
        const newWorkerId = parseInt(event.target.value, 10);
        updatingWorkerIndex = video.Index;

        try {
            const response = await fetch('/api/assign-worker', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    videoIndex: video.Index,
                    workerId: newWorkerId
                })
            });

            if (!response.ok) {
                const errData = await response.json();
                throw new Error(errData.message || 'Failed to assign worker.');
            }

            // ✅ 반응성 갱신
            video.WorkerID = newWorkerId;
            allSegments = allSegments.map(v =>
                v.Index === video.Index ? { ...v, WorkerID: newWorkerId } : v
            );

            await tick();
            console.log(`[Success] Video ${video.Index} assigned to Worker ${newWorkerId}`);
        } catch (err) {
            console.error(err);
            event.target.value = String(video.WorkerID || '0');
        } finally {
            updatingWorkerIndex = null;
        }
    }


	/**
	 * Handles the deletion of a video and its descendants.
	 */
	async function handleDelete(video: Video, type: '원본' | 'Crop' | '구간') {
		const fileName = path.pop(video.LocationFile);

		const confirmationMessage = `[Permanent Deletion Warning]
Are you sure you want to delete this ${type} video?

- Target: ${fileName} (Index: ${video.Index})

This action will permanently delete not only the selected video but also all descendant videos, tens of thousands of frame images, and all related database information from the server. This action cannot be undone.`;

		if (!confirm(confirmationMessage)) {
			return;
		}

		isLoading = true;
		message = `[Index: ${video.Index}] Deletion in progress...`;

		try {
			const response = await fetch(`/api/delete-video-recursive?index=${video.Index}`, {
				method: 'DELETE'
			});

			if (!response.ok) {
				const errData = await response.json().catch(() => ({
					message: 'Response is not valid JSON.'
				}));
				throw new Error(errData.message || 'An error occurred during deletion on the server.');
			}

			// Reset UI state on successful deletion
			if (selectedVideoForPlayer?.Index === video.Index) {
				videoURL = '';
				selectedVideoForPlayer = null;
			}
			if (selectedOriginal?.Index === video.Index) selectedOriginal = null;
			if (selectedCrop?.Index === video.Index) selectedCrop = null;

			await loadAllVideos(); // Reload list to reflect changes
			message = `[Index: ${video.Index}] Deletion complete.`;
		} catch (err: any) {
			message = `Deletion failed: ${err.message}`;
			console.error('[Delete] Error in handleDelete function:', err);
			isLoading = false; // Ensure loading is stopped on error
		}
	}
</script>

<svelte:head>
	<title>3단계: 동영상 관리</title>
</svelte:head>

<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">
			🎬 3단계: 동영상 관리
		</h1>
	</div>

	{#if message}
		<p
			class="p-4 mb-6 text-center rounded-lg"
			class:bg-blue-50={!message.includes('Error')}
			class:text-blue-700={!message.includes('Error')}
			class:bg-red-50={message.includes('Error')}
			class:text-red-700={message.includes('Error')}
		>
			{message}
		</p>
	{/if}

	<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-start">
		<!-- Video Player Section -->
		<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6 sticky top-8">
			<h2 class="text-xl font-semibold text-gray-800 mb-4">
				Video Preview
				{#if selectedVideoForPlayer}
					<span class="text-sm font-normal text-gray-500 ml-2"
						>(ID: {selectedVideoForPlayer.Index})</span
					>
				{/if}
			</h2>
			{#if videoURL}
				{#key videoURL}
					<video src={videoURL} class="w-full rounded-lg bg-gray-100" controls autoplay>
						Your browser does not support the video tag.
					</video>
				{/key}
			{:else}
				<div class="aspect-video w-full flex items-center justify-center bg-gray-100 rounded-lg">
					<p class="text-gray-500">Select a video from the list to play.</p>
				</div>
			{/if}
		</section>

		<!-- Original and Crop Lists Section -->
		<div class="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">
					Original List ({originals.length})
				</h2>
				<ul class="h-64 overflow-y-auto space-y-2 pr-2">
					{#each originals as video (video.Index)}
						<li
							class="flex items-center justify-between p-2 rounded-md cursor-pointer"
							class:bg-blue-100={selectedOriginal?.Index === video.Index}
							class:hover:bg-gray-50={selectedOriginal?.Index !== video.Index}
						>
							<span
								class="truncate flex-1"
								on:click={() => handleOriginalSelect(video)}
								title={video.LocationFile}
							>
								{path.pop(video.LocationFile)} (ID: {video.Index})
							</span>
							<button
								on:click|stopPropagation={() => handleDelete(video, '원본')}
								disabled={isLoading}
								class="text-red-500 hover:text-red-700 font-bold px-2 disabled:opacity-50 flex-shrink-0 ml-2"
								title="Permanently delete this original and all related crops and segments"
							>
								삭제
							</button>
						</li>
					{:else}
						<li class="text-gray-500 text-center pt-4">No original videos found.</li>
					{/each}
				</ul>
			</section>

			<section
				class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6"
				class:opacity-50={!selectedOriginal}
			>
				<h2 class="text-xl font-semibold text-gray-800 mb-4">
					Crop List ({filteredCrops.length})
				</h2>
				<ul class="h-64 overflow-y-auto space-y-2 pr-2">
					{#if selectedOriginal}
						{#each filteredCrops as video (video.Index)}
							<li
								class="flex items-center justify-between p-2 rounded-md cursor-pointer"
								class:bg-blue-100={selectedCrop?.Index === video.Index}
								class:hover:bg-gray-50={selectedCrop?.Index !== video.Index}
							>
								<span
									class="truncate flex-1"
									on:click={() => handleCropSelect(video)}
									title={video.LocationFile}
								>
									{path.pop(video.LocationFile)} (ID: {video.Index})
								</span>
								<button
									on:click|stopPropagation={() => handleDelete(video, 'Crop')}
									disabled={isLoading}
									class="text-red-500 hover:text-red-700 font-bold px-2 disabled:opacity-50 flex-shrink-0 ml-2"
									title="Permanently delete this crop and all related segments"
								>
									삭제
								</button>
							</li>
						{:else}
							<li class="text-gray-500 text-center pt-4">No cropped videos for the selected original.</li>
						{/each}
					{:else}
						<li class="text-gray-500 text-center pt-4">Select an original video first.</li>
					{/if}
				</ul>
			</section>
		</div>

		<!-- Segments List Section -->
		<section class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-xl p-6" class:opacity-50={!selectedCrop}>
			<h2 class="text-xl font-semibold text-gray-800 mb-4">
				Saved Segments List ({filteredSegments.length})
			</h2>
			<ul class="h-[33.5rem] overflow-y-auto space-y-2 pr-2">
				{#if selectedCrop}
					{#each filteredSegments as video (video.Index)}
						<li
							class="flex items-center justify-between p-2 rounded-md"
							class:bg-blue-100={selectedVideoForPlayer?.Index === video.Index}
							class:hover:bg-gray-50={selectedVideoForPlayer?.Index !== video.Index}
						>
							<span
								class="truncate flex-1 cursor-pointer"
								on:click={() => playVideo(video)}
								title={video.LocationFile}
							>
								{path.pop(video.LocationFile)} (ID: {video.Index})
							</span>

							<select
                                value={String(video.WorkerID || '0')}
                                on:change={(e) => handleWorkerChange(video, e)}
                                on:click|stopPropagation
                                disabled={updatingWorkerIndex === video.Index || isLoading}
                                class="text-sm rounded border-gray-300 py-1 px-2 mx-2 flex-shrink-0
                                        disabled:opacity-50 disabled:bg-gray-100 cursor-pointer"
                            >
                                <option value="0">[Unassigned]</option>
                                {#each workers as worker (worker.id)}
                                    <option value={String(worker.id)}>{worker.name}</option>
                                {/each}
                            </select>
							<button
								on:click|stopPropagation={() => handleDelete(video, '구간')}
								disabled={isLoading}
								class="text-red-500 hover:text-red-700 font-bold px-1 disabled:opacity-50 flex-shrink-0"
								title="Permanently delete this segment"
							>
								삭제
							</button>
						</li>
					{:else}
						<li class="text-gray-500 text-center pt-4">No saved segments for the selected crop.</li>
					{/each}
				{:else}
					<li class="text-gray-500 text-center pt-4">Select a cropped video first.</li>
				{/if}
			</ul>
		</section>
	</div>
</main>

