<script lang="ts">
	import { SvelteMap, SvelteSet } from 'svelte/reactivity';
	import type { SessionType, SessionImage, SessionVideo } from './types';
	import {
		getSessionColorClasses,
		formatDateTime,
		getAuthenticatedImageUrl,
		revokeAuthenticatedUrl
	} from './types';

	interface Props {
		sessionType: SessionType;
		photos: SessionImage[];
		videos: SessionVideo[];
		isActive: boolean;
		getTeamMemberName: (id: string | null | undefined) => string;
		onUploadPhoto?: (file: File, title: string, notes: string, internal: boolean) => Promise<void>;
		onUploadVideo?: (file: File, title: string, notes: string, internal: boolean) => Promise<void>;
		onUpdatePhoto?: (
			photoId: string,
			title: string,
			notes: string,
			internal: boolean
		) => Promise<void>;
		onUpdateVideo?: (
			videoId: string,
			title: string,
			notes: string,
			internal: boolean
		) => Promise<void>;
		onDeletePhoto?: (photoId: string) => Promise<void>;
		onDeleteVideo?: (videoId: string) => Promise<void>;
	}

	const {
		sessionType,
		photos,
		videos,
		isActive,
		getTeamMemberName,
		onUploadPhoto,
		onUploadVideo,
		onUpdatePhoto,
		onUpdateVideo,
		onDeletePhoto,
		onDeleteVideo
	}: Props = $props();

	const colors = $derived(getSessionColorClasses(sessionType));

	// ============ STAGED PHOTO UPLOAD STATE ============
	interface StagedPhoto {
		id: string;
		file: File;
		previewUrl: string | null; // null for HEIC files
		isHeic: boolean;
		title: string;
		notes: string;
		internal: boolean;
		uploading: boolean;
		error?: string;
	}

	let stagedPhotos = $state<StagedPhoto[]>([]);
	let defaultPhotoInternal = $state(true);
	let showPhotoUploadForm = $state(false);
	let photoFileInput = $state<HTMLInputElement | null>(null);

	// Bulk upload progress
	let uploadProgress = $state<{ completed: number; total: number; failed: number } | null>(null);

	// ============ STAGED VIDEO UPLOAD STATE ============
	let stagedVideo = $state<{
		file: File;
		previewUrl: string | null;
		title: string;
		notes: string;
		internal: boolean;
	} | null>(null);
	let showVideoUploadForm = $state(false);
	let videoFileInput = $state<HTMLInputElement | null>(null);
	let isUploadingVideo = $state(false);
	let videoUploadError = $state<string | null>(null);

	// ============ EXISTING MEDIA STATE ============
	let selectedPhoto = $state<SessionImage | null>(null);
	let selectedVideo = $state<SessionVideo | null>(null);
	let editTitle = $state('');
	let editNotes = $state('');
	let editInternal = $state(false);
	let isUpdating = $state(false);
	let deletingId = $state<string | null>(null);

	// Cached authenticated URLs - keyed by URL path
	let authenticatedUrls = new SvelteMap<string, string>();
	let fetchingUrls = new SvelteSet<string>();

	// Load authenticated URLs for photos and videos
	$effect(() => {
		// Load photo URLs (both thumbnail and full image)
		photos?.forEach(async (photo) => {
			// Fetch thumbnail URL
			const thumbnailPath = photo.thumbnail || photo.image;
			if (
				thumbnailPath &&
				!authenticatedUrls.has(thumbnailPath) &&
				!fetchingUrls.has(thumbnailPath)
			) {
				fetchingUrls.add(thumbnailPath);
				try {
					const url = await getAuthenticatedImageUrl(thumbnailPath);
					authenticatedUrls.set(thumbnailPath, url);
				} catch (err) {
					console.error('Failed to load photo thumbnail:', photo.id, err);
				} finally {
					fetchingUrls.delete(thumbnailPath);
				}
			}

			// Also fetch full image URL if different from thumbnail
			if (
				photo.image !== thumbnailPath &&
				!authenticatedUrls.has(photo.image) &&
				!fetchingUrls.has(photo.image)
			) {
				fetchingUrls.add(photo.image);
				try {
					const url = await getAuthenticatedImageUrl(photo.image);
					authenticatedUrls.set(photo.image, url);
				} catch (err) {
					console.error('Failed to load full photo:', photo.id, err);
				} finally {
					fetchingUrls.delete(photo.image);
				}
			}
		});

		// Load video thumbnail and video URLs
		videos?.forEach(async (video) => {
			// Fetch thumbnail
			if (
				video.thumbnail &&
				!authenticatedUrls.has(video.thumbnail) &&
				!fetchingUrls.has(video.thumbnail)
			) {
				fetchingUrls.add(video.thumbnail);
				try {
					const url = await getAuthenticatedImageUrl(video.thumbnail);
					authenticatedUrls.set(video.thumbnail, url);
				} catch (err) {
					console.error('Failed to load video thumbnail:', video.id, err);
				} finally {
					fetchingUrls.delete(video.thumbnail);
				}
			}

			// Fetch video URL
			if (video.video && !authenticatedUrls.has(video.video) && !fetchingUrls.has(video.video)) {
				fetchingUrls.add(video.video);
				try {
					const url = await getAuthenticatedImageUrl(video.video);
					authenticatedUrls.set(video.video, url);
				} catch (err) {
					console.error('Failed to load video URL:', video.id, err);
				} finally {
					fetchingUrls.delete(video.video);
				}
			}
		});
	});

	// Track which media is being opened (for loading spinner)
	let openingMediaPath = $state<string | null>(null);

	// Open media in new tab (with loading state if not ready)
	async function openInNewTab(fullPath: string | undefined) {
		if (!fullPath) return;

		// If already loaded, open immediately
		const existingUrl = authenticatedUrls.get(fullPath);
		if (existingUrl) {
			window.open(existingUrl, '_blank');
			return;
		}

		// Show loading state and fetch
		openingMediaPath = fullPath;
		try {
			const url = await getAuthenticatedImageUrl(fullPath);
			authenticatedUrls.set(fullPath, url);
			window.open(url, '_blank');
		} catch (err) {
			console.error('Failed to load media:', err);
		} finally {
			openingMediaPath = null;
		}
	}

	// ============ PHOTO UPLOAD FUNCTIONS ============
	const MAX_PHOTO_SIZE = 10 * 1024 * 1024; // 10MB

	function isHeicFile(file: File): boolean {
		const name = file.name.toLowerCase();
		return (
			name.endsWith('.heic') ||
			name.endsWith('.heif') ||
			file.type === 'image/heic' ||
			file.type === 'image/heif'
		);
	}

	function generateId(): string {
		return Math.random().toString(36).substring(2, 11);
	}

	function getFilenameWithoutExtension(filename: string): string {
		return filename.replace(/\.[^/.]+$/, '');
	}

	function handlePhotoFileSelect(event: Event) {
		const input = event.target as HTMLInputElement;
		if (!input.files || input.files.length === 0) return;

		const validFiles: File[] = [];
		const rejectedFiles: string[] = [];

		for (const file of Array.from(input.files)) {
			if (file.size > MAX_PHOTO_SIZE) {
				const sizeMB = (file.size / (1024 * 1024)).toFixed(1);
				rejectedFiles.push(`${file.name} (${sizeMB}MB - max 10MB)`);
			} else {
				validFiles.push(file);
			}
		}

		if (rejectedFiles.length > 0) {
			alert(
				`The following files are too large:\n\n${rejectedFiles.join('\n')}\n\nMaximum size is 10MB per photo.`
			);
		}

		// Stage valid files
		for (const file of validFiles) {
			const isHeic = isHeicFile(file);
			const previewUrl = isHeic ? null : URL.createObjectURL(file);

			stagedPhotos = [
				...stagedPhotos,
				{
					id: generateId(),
					file,
					previewUrl,
					isHeic,
					title: getFilenameWithoutExtension(file.name),
					notes: '',
					internal: defaultPhotoInternal,
					uploading: false
				}
			];
		}

		// Reset input
		input.value = '';

		// Show form if we have staged photos
		if (stagedPhotos.length > 0) {
			showPhotoUploadForm = true;
		}
	}

	function removeStagedPhoto(id: string) {
		const photo = stagedPhotos.find((p) => p.id === id);
		if (photo?.previewUrl) {
			URL.revokeObjectURL(photo.previewUrl);
		}
		stagedPhotos = stagedPhotos.filter((p) => p.id !== id);

		if (stagedPhotos.length === 0) {
			showPhotoUploadForm = false;
		}
	}

	function cancelPhotoUpload() {
		// Revoke all preview URLs
		for (const photo of stagedPhotos) {
			if (photo.previewUrl) {
				URL.revokeObjectURL(photo.previewUrl);
			}
		}
		stagedPhotos = [];
		showPhotoUploadForm = false;
		uploadProgress = null;
	}

	async function handleBulkPhotoUpload() {
		if (stagedPhotos.length === 0 || !onUploadPhoto) return;

		const total = stagedPhotos.length;
		uploadProgress = { completed: 0, total, failed: 0 };

		// Upload one at a time for mobile bandwidth
		for (let i = 0; i < stagedPhotos.length; i++) {
			const photo = stagedPhotos[i];

			// Mark as uploading
			stagedPhotos = stagedPhotos.map((p) =>
				p.id === photo.id ? { ...p, uploading: true, error: undefined } : p
			);

			try {
				await onUploadPhoto(photo.file, photo.title, photo.notes, photo.internal);

				// Success - remove from staged
				if (photo.previewUrl) {
					URL.revokeObjectURL(photo.previewUrl);
				}
				stagedPhotos = stagedPhotos.filter((p) => p.id !== photo.id);

				uploadProgress = {
					...uploadProgress!,
					completed: uploadProgress!.completed + 1
				};

				// Adjust index since we removed an item
				i--;
			} catch (err) {
				const errorMessage = err instanceof Error ? err.message : 'Upload failed';
				stagedPhotos = stagedPhotos.map((p) =>
					p.id === photo.id ? { ...p, uploading: false, error: errorMessage } : p
				);
				uploadProgress = {
					...uploadProgress!,
					completed: uploadProgress!.completed + 1,
					failed: uploadProgress!.failed + 1
				};
			}
		}

		// Clean up if all succeeded
		if (stagedPhotos.length === 0) {
			showPhotoUploadForm = false;
		}
		uploadProgress = null;
	}

	// ============ VIDEO UPLOAD FUNCTIONS ============
	const MAX_VIDEO_SIZE = 50 * 1024 * 1024; // 50MB

	function handleVideoFileSelect(event: Event) {
		const input = event.target as HTMLInputElement;
		const file = input.files?.[0];
		if (!file) return;

		if (file.size > MAX_VIDEO_SIZE) {
			const sizeMB = (file.size / (1024 * 1024)).toFixed(1);
			alert(`Video is too large (${sizeMB}MB).\n\nMaximum size is 50MB.`);
			input.value = '';
			return;
		}

		// Clean up previous preview
		if (stagedVideo?.previewUrl) {
			URL.revokeObjectURL(stagedVideo.previewUrl);
		}

		stagedVideo = {
			file,
			previewUrl: URL.createObjectURL(file),
			title: getFilenameWithoutExtension(file.name),
			notes: '',
			internal: true
		};
		showVideoUploadForm = true;
		input.value = '';
	}

	function cancelVideoUpload() {
		if (stagedVideo?.previewUrl) {
			URL.revokeObjectURL(stagedVideo.previewUrl);
		}
		stagedVideo = null;
		showVideoUploadForm = false;
		videoUploadError = null;
	}

	async function handleVideoUpload() {
		if (!stagedVideo || !onUploadVideo) return;

		isUploadingVideo = true;
		videoUploadError = null;

		try {
			await onUploadVideo(
				stagedVideo.file,
				stagedVideo.title,
				stagedVideo.notes,
				stagedVideo.internal
			);

			// Success - clean up
			if (stagedVideo.previewUrl) {
				URL.revokeObjectURL(stagedVideo.previewUrl);
			}
			stagedVideo = null;
			showVideoUploadForm = false;
		} catch (err) {
			videoUploadError = err instanceof Error ? err.message : 'Upload failed';
		} finally {
			isUploadingVideo = false;
		}
	}

	// ============ EDIT/DELETE EXISTING MEDIA ============
	function openPhotoEditor(photo: SessionImage) {
		selectedPhoto = photo;
		editTitle = photo.title || '';
		editNotes = photo.notes || '';
		editInternal = photo.internal;
	}

	function openVideoEditor(video: SessionVideo) {
		selectedVideo = video;
		editTitle = video.title || '';
		editNotes = video.notes || '';
		editInternal = video.internal;
	}

	function closeEditor() {
		selectedPhoto = null;
		selectedVideo = null;
		editTitle = '';
		editNotes = '';
		editInternal = false;
	}

	async function handleUpdateMedia() {
		isUpdating = true;
		try {
			if (selectedPhoto && onUpdatePhoto) {
				await onUpdatePhoto(selectedPhoto.id, editTitle, editNotes, editInternal);
			} else if (selectedVideo && onUpdateVideo) {
				await onUpdateVideo(selectedVideo.id, editTitle, editNotes, editInternal);
			}
			closeEditor();
		} finally {
			isUpdating = false;
		}
	}

	async function handleDeletePhoto(id: string) {
		if (!onDeletePhoto) return;
		deletingId = id;
		try {
			await onDeletePhoto(id);
			if (selectedPhoto?.id === id) closeEditor();
		} finally {
			deletingId = null;
		}
	}

	async function handleDeleteVideo(id: string) {
		if (!onDeleteVideo) return;
		deletingId = id;
		try {
			await onDeleteVideo(id);
			if (selectedVideo?.id === id) closeEditor();
		} finally {
			deletingId = null;
		}
	}
</script>

<div class="space-y-6">
	<!-- Upload Buttons (only for active sessions) -->
	{#if isActive && (onUploadPhoto || onUploadVideo)}
		<div class="flex gap-2">
			<!-- Hidden file inputs -->
			<input
				bind:this={photoFileInput}
				type="file"
				class="hidden"
				accept="image/*"
				multiple
				onchange={handlePhotoFileSelect}
			/>
			<input
				bind:this={videoFileInput}
				type="file"
				class="hidden"
				accept="video/*"
				onchange={handleVideoFileSelect}
			/>

			{#if onUploadPhoto}
				<button
					type="button"
					class="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
					onclick={() => photoFileInput?.click()}
					disabled={showPhotoUploadForm}
				>
					<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							stroke-width="2"
							d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
						></path>
					</svg>
					<span>Add Photos</span>
				</button>
			{/if}

			{#if onUploadVideo}
				<button
					type="button"
					class="inline-flex items-center gap-2 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
					onclick={() => videoFileInput?.click()}
					disabled={showVideoUploadForm}
				>
					<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							stroke-width="2"
							d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"
						></path>
					</svg>
					<span>Add Video</span>
				</button>
			{/if}
		</div>
	{/if}

	<!-- Photo Upload Form (staged photos) -->
	{#if showPhotoUploadForm && stagedPhotos.length > 0}
		<div class="rounded-lg border {colors.borderLight} bg-white p-4 dark:bg-gray-800">
			<div class="mb-4 flex items-center justify-between">
				<h4 class="font-medium text-gray-900 dark:text-gray-100">
					{stagedPhotos.length} photo{stagedPhotos.length !== 1 ? 's' : ''} ready to upload
				</h4>
				<button
					type="button"
					class="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
					onclick={() => photoFileInput?.click()}
				>
					+ Add more
				</button>
			</div>

			<!-- Default internal checkbox -->
			<label class="mb-4 flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
				<input
					type="checkbox"
					class="rounded border-gray-300 dark:border-gray-600 dark:bg-gray-700"
					checked={defaultPhotoInternal}
					onchange={(e) => {
						defaultPhotoInternal = e.currentTarget.checked;
						// Apply to all staged photos
						stagedPhotos = stagedPhotos.map((p) => ({ ...p, internal: defaultPhotoInternal }));
					}}
				/>
				<span>Mark all as internal only</span>
			</label>

			<!-- Staged photos grid -->
			<div class="mb-4 space-y-3">
				{#each stagedPhotos as photo (photo.id)}
					<div
						class="flex gap-3 rounded-lg border border-gray-200 p-3 dark:border-gray-700 {photo.uploading
							? 'opacity-60'
							: ''} {photo.error
							? 'border-red-300 bg-red-50 dark:border-red-700 dark:bg-red-900/20'
							: ''}"
					>
						<!-- Preview -->
						<div
							class="flex h-20 w-20 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-700"
						>
							{#if photo.previewUrl}
								<img src={photo.previewUrl} alt="Preview" class="h-full w-full object-cover" />
							{:else if photo.isHeic}
								<!-- HEIC placeholder -->
								<div class="flex flex-col items-center justify-center text-center">
									<svg
										class="h-8 w-8 text-gray-400"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="1.5"
											d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
										></path>
									</svg>
									<span class="mt-1 text-xs font-medium text-gray-500">HEIC</span>
								</div>
							{/if}
						</div>

						<!-- Editable fields -->
						<div class="min-w-0 flex-1 space-y-2">
							<input
								type="text"
								class="w-full rounded border border-gray-300 px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
								placeholder="Title"
								value={photo.title}
								oninput={(e) => {
									stagedPhotos = stagedPhotos.map((p) =>
										p.id === photo.id ? { ...p, title: e.currentTarget.value } : p
									);
								}}
								disabled={photo.uploading}
							/>
							<textarea
								class="w-full rounded border border-gray-300 px-2 py-1 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
								placeholder="Notes (optional)"
								rows="1"
								oninput={(e) => {
									stagedPhotos = stagedPhotos.map((p) =>
										p.id === photo.id ? { ...p, notes: e.currentTarget.value } : p
									);
								}}
								disabled={photo.uploading}>{photo.notes}</textarea
							>
							<label class="flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-400">
								<input
									type="checkbox"
									class="rounded border-gray-300 dark:border-gray-600"
									checked={photo.internal}
									onchange={(e) => {
										stagedPhotos = stagedPhotos.map((p) =>
											p.id === photo.id ? { ...p, internal: e.currentTarget.checked } : p
										);
									}}
									disabled={photo.uploading}
								/>
								<span>Internal</span>
							</label>
							{#if photo.error}
								<p class="text-xs text-red-600 dark:text-red-400">{photo.error}</p>
							{/if}
						</div>

						<!-- Remove button -->
						{#if !photo.uploading}
							<button
								type="button"
								class="shrink-0 self-start p-1 text-gray-400 hover:text-red-500"
								onclick={() => removeStagedPhoto(photo.id)}
								aria-label="Remove photo"
							>
								<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
									<path
										stroke-linecap="round"
										stroke-linejoin="round"
										stroke-width="2"
										d="M6 18L18 6M6 6l12 12"
									></path>
								</svg>
							</button>
						{:else}
							<div class="shrink-0 self-start p-1">
								<svg class="h-5 w-5 animate-spin text-gray-400" fill="none" viewBox="0 0 24 24">
									<circle
										class="opacity-25"
										cx="12"
										cy="12"
										r="10"
										stroke="currentColor"
										stroke-width="4"
									></circle>
									<path
										class="opacity-75"
										fill="currentColor"
										d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
									></path>
								</svg>
							</div>
						{/if}
					</div>
				{/each}
			</div>

			<!-- Progress bar -->
			{#if uploadProgress}
				<div class="mb-4 rounded-lg border {colors.borderLight} bg-gray-50 p-3 dark:bg-gray-900">
					<div class="mb-2 flex items-center justify-between text-sm">
						<span class="font-medium text-gray-700 dark:text-gray-300">
							Uploading {uploadProgress.completed} of {uploadProgress.total}...
						</span>
						{#if uploadProgress.failed > 0}
							<span class="text-red-500">{uploadProgress.failed} failed</span>
						{/if}
					</div>
					<div class="h-2 w-full overflow-hidden rounded-full bg-gray-200 dark:bg-gray-700">
						<div
							class="h-full rounded-full transition-all duration-300 {colors.bg}"
							style="width: {(uploadProgress.completed / uploadProgress.total) * 100}%"
						></div>
					</div>
				</div>
			{/if}

			<!-- Action buttons -->
			<div class="flex justify-end gap-2">
				<button
					type="button"
					class="rounded-lg px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
					onclick={cancelPhotoUpload}
					disabled={uploadProgress !== null}
				>
					Cancel
				</button>
				<button
					type="button"
					class="rounded-lg px-4 py-2 text-sm font-medium text-white {colors.bg} hover:opacity-90"
					onclick={handleBulkPhotoUpload}
					disabled={uploadProgress !== null}
				>
					Upload {stagedPhotos.length} Photo{stagedPhotos.length !== 1 ? 's' : ''}
				</button>
			</div>
		</div>
	{/if}

	<!-- Video Upload Form -->
	{#if showVideoUploadForm && stagedVideo}
		<div class="rounded-lg border {colors.borderLight} bg-white p-4 dark:bg-gray-800">
			<h4 class="mb-4 font-medium text-gray-900 dark:text-gray-100">Upload Video</h4>

			<div class="mb-4 flex gap-4">
				<!-- Video preview -->
				{#if stagedVideo.previewUrl}
					<div class="h-32 w-48 shrink-0 overflow-hidden rounded-lg bg-black">
						<video src={stagedVideo.previewUrl} class="h-full w-full object-contain" controls
						></video>
					</div>
				{/if}

				<!-- Editable fields -->
				<div class="min-w-0 flex-1 space-y-3">
					<label class="block">
						<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Title</span>
						<input
							type="text"
							class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
							value={stagedVideo.title}
							oninput={(e) => {
								if (stagedVideo) stagedVideo.title = e.currentTarget.value;
							}}
							disabled={isUploadingVideo}
						/>
					</label>

					<label class="block">
						<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Notes</span>
						<textarea
							class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
							rows="2"
							oninput={(e) => {
								if (stagedVideo) stagedVideo.notes = e.currentTarget.value;
							}}
							disabled={isUploadingVideo}>{stagedVideo.notes}</textarea
						>
					</label>

					<label class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
						<input
							type="checkbox"
							class="rounded border-gray-300 dark:border-gray-600"
							checked={stagedVideo.internal}
							onchange={(e) => {
								if (stagedVideo) stagedVideo.internal = e.currentTarget.checked;
							}}
							disabled={isUploadingVideo}
						/>
						<span>Internal only</span>
					</label>
				</div>
			</div>

			{#if videoUploadError}
				<div
					class="mb-4 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-800 dark:bg-red-900/20"
				>
					<p class="text-sm text-red-700 dark:text-red-400">{videoUploadError}</p>
				</div>
			{/if}

			<div class="flex justify-end gap-2">
				<button
					type="button"
					class="rounded-lg px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
					onclick={cancelVideoUpload}
					disabled={isUploadingVideo}
				>
					Cancel
				</button>
				<button
					type="button"
					class="inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white {colors.bg} hover:opacity-90"
					onclick={handleVideoUpload}
					disabled={isUploadingVideo}
				>
					{#if isUploadingVideo}
						<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
							<circle
								class="opacity-25"
								cx="12"
								cy="12"
								r="10"
								stroke="currentColor"
								stroke-width="4"
							></circle>
							<path
								class="opacity-75"
								fill="currentColor"
								d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
							></path>
						</svg>
					{/if}
					<span>Upload Video</span>
				</button>
			</div>
		</div>
	{/if}

	<!-- Existing Photos Grid -->
	{#if photos.length > 0}
		<div>
			<h4 class="mb-3 font-medium text-gray-900 dark:text-gray-100">Photos ({photos.length})</h4>
			<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
				{#each photos as photo (photo.id)}
					{@const thumbnailPath = photo.thumbnail || photo.image}
					<div class="relative overflow-hidden rounded-lg bg-gray-100 dark:bg-gray-800">
						<!-- Image -->
						<button
							type="button"
							class="block aspect-square w-full"
							onclick={() => openInNewTab(photo.image)}
							aria-label="View {photo.title || 'photo'} full size"
						>
							{#if authenticatedUrls.has(thumbnailPath)}
								<img
									src={authenticatedUrls.get(thumbnailPath)}
									alt={photo.title || 'Session photo'}
									class="h-full w-full object-cover"
								/>
							{:else}
								<span class="flex h-full w-full items-center justify-center">
									<span class="h-8 w-8 animate-pulse rounded-full bg-gray-300 dark:bg-gray-600"
									></span>
								</span>
							{/if}

							<!-- Loading spinner when opening full image -->
							{#if openingMediaPath === photo.image}
								<span class="absolute inset-0 flex items-center justify-center bg-black/50">
									<svg class="h-8 w-8 animate-spin text-white" fill="none" viewBox="0 0 24 24">
										<circle
											class="opacity-25"
											cx="12"
											cy="12"
											r="10"
											stroke="currentColor"
											stroke-width="4"
										></circle>
										<path
											class="opacity-75"
											fill="currentColor"
											d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
										></path>
									</svg>
								</span>
							{/if}
						</button>

						<!-- Internal badge -->
						{#if photo.internal}
							<span
								class="absolute top-2 left-2 rounded bg-amber-500/90 px-1.5 py-0.5 text-xs font-medium text-white"
							>
								Internal
							</span>
						{/if}

						<!-- Edit/Delete buttons (always visible) -->
						{#if isActive && (onUpdatePhoto || onDeletePhoto)}
							<div class="absolute top-2 right-2 flex gap-1">
								{#if onUpdatePhoto}
									<button
										type="button"
										class="rounded bg-white/90 p-1.5 text-gray-600 dark:bg-gray-800/90 dark:text-gray-300"
										onclick={() => openPhotoEditor(photo)}
										aria-label="Edit photo"
									>
										<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
											<path
												stroke-linecap="round"
												stroke-linejoin="round"
												stroke-width="2"
												d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
											></path>
										</svg>
									</button>
								{/if}
								{#if onDeletePhoto}
									<button
										type="button"
										class="rounded bg-white/90 p-1.5 text-gray-600 dark:bg-gray-800/90 dark:text-gray-300"
										onclick={() => handleDeletePhoto(photo.id)}
										disabled={deletingId === photo.id}
										aria-label="Delete photo"
									>
										{#if deletingId === photo.id}
											<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
												<circle
													class="opacity-25"
													cx="12"
													cy="12"
													r="10"
													stroke="currentColor"
													stroke-width="4"
												></circle>
												<path
													class="opacity-75"
													fill="currentColor"
													d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
												></path>
											</svg>
										{:else}
											<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
												<path
													stroke-linecap="round"
													stroke-linejoin="round"
													stroke-width="2"
													d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
												></path>
											</svg>
										{/if}
									</button>
								{/if}
							</div>
						{/if}

						<!-- Overlay with title/notes/author -->
						<div
							class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent p-2"
						>
							<p class="truncate text-xs font-medium text-white">{photo.title || 'Untitled'}</p>
							{#if photo.notes}
								<p class="truncate text-xs text-white/80">{photo.notes}</p>
							{/if}
							<p class="text-xs text-white/70">{getTeamMemberName(photo.uploadedById)}</p>
						</div>
					</div>
				{/each}
			</div>
		</div>
	{/if}

	<!-- Existing Videos Grid -->
	{#if videos.length > 0}
		<div>
			<h4 class="mb-3 font-medium text-gray-900 dark:text-gray-100">Videos ({videos.length})</h4>
			<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
				{#each videos as video (video.id)}
					<div class="relative overflow-hidden rounded-lg bg-gray-900">
						<!-- Video thumbnail / placeholder -->
						<button
							type="button"
							class="block aspect-video w-full"
							onclick={() => openInNewTab(video.video)}
							aria-label="Play {video.title || 'video'}"
						>
							{#if video.thumbnail && authenticatedUrls.has(video.thumbnail)}
								<img
									src={authenticatedUrls.get(video.thumbnail)}
									alt={video.title || 'Video thumbnail'}
									class="h-full w-full object-cover"
								/>
							{:else}
								<span class="flex h-full w-full items-center justify-center bg-gray-800">
									<svg
										class="h-12 w-12 text-gray-500"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="1.5"
											d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"
										></path>
									</svg>
								</span>
							{/if}

							<!-- Play icon overlay (or loading spinner) -->
							<span class="pointer-events-none absolute inset-0 flex items-center justify-center">
								{#if openingMediaPath === video.video}
									<span class="rounded-full bg-black/70 p-3">
										<svg class="h-6 w-6 animate-spin text-white" fill="none" viewBox="0 0 24 24">
											<circle
												class="opacity-25"
												cx="12"
												cy="12"
												r="10"
												stroke="currentColor"
												stroke-width="4"
											></circle>
											<path
												class="opacity-75"
												fill="currentColor"
												d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
											></path>
										</svg>
									</span>
								{:else}
									<span class="rounded-full bg-black/50 p-3">
										<svg class="h-6 w-6 text-white" fill="currentColor" viewBox="0 0 24 24">
											<path d="M8 5v14l11-7z" />
										</svg>
									</span>
								{/if}
							</span>
						</button>

						<!-- Internal badge -->
						{#if video.internal}
							<span
								class="absolute top-2 left-2 rounded bg-amber-500/90 px-1.5 py-0.5 text-xs font-medium text-white"
							>
								Internal
							</span>
						{/if}

						<!-- Edit/Delete buttons (always visible) -->
						{#if isActive && (onUpdateVideo || onDeleteVideo)}
							<div class="absolute top-2 right-2 flex gap-1">
								{#if onUpdateVideo}
									<button
										type="button"
										class="rounded bg-white/90 p-1.5 text-gray-600 dark:bg-gray-800/90 dark:text-gray-300"
										onclick={() => openVideoEditor(video)}
										aria-label="Edit video"
									>
										<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
											<path
												stroke-linecap="round"
												stroke-linejoin="round"
												stroke-width="2"
												d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
											></path>
										</svg>
									</button>
								{/if}
								{#if onDeleteVideo}
									<button
										type="button"
										class="rounded bg-white/90 p-1.5 text-gray-600 dark:bg-gray-800/90 dark:text-gray-300"
										onclick={() => handleDeleteVideo(video.id)}
										disabled={deletingId === video.id}
										aria-label="Delete video"
									>
										{#if deletingId === video.id}
											<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
												<circle
													class="opacity-25"
													cx="12"
													cy="12"
													r="10"
													stroke="currentColor"
													stroke-width="4"
												></circle>
												<path
													class="opacity-75"
													fill="currentColor"
													d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
												></path>
											</svg>
										{:else}
											<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
												<path
													stroke-linecap="round"
													stroke-linejoin="round"
													stroke-width="2"
													d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
												></path>
											</svg>
										{/if}
									</button>
								{/if}
							</div>
						{/if}

						<!-- Overlay with title/notes/author -->
						<div
							class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent p-2"
						>
							<p class="truncate text-xs font-medium text-white">{video.title || 'Untitled'}</p>
							{#if video.notes}
								<p class="truncate text-xs text-white/80">{video.notes}</p>
							{/if}
							<p class="text-xs text-white/70">
								{getTeamMemberName(video.uploadedById)}
								{#if video.durationSeconds}
									· {Math.floor(video.durationSeconds / 60)}:{(video.durationSeconds % 60)
										.toString()
										.padStart(2, '0')}
								{/if}
							</p>
						</div>
					</div>
				{/each}
			</div>
		</div>
	{/if}

	<!-- Empty State -->
	{#if photos.length === 0 && videos.length === 0 && !showPhotoUploadForm && !showVideoUploadForm}
		<div class="py-8 text-center">
			<svg
				class="mx-auto h-12 w-12 text-gray-300 dark:text-gray-600"
				fill="none"
				viewBox="0 0 24 24"
				stroke="currentColor"
			>
				<path
					stroke-linecap="round"
					stroke-linejoin="round"
					stroke-width="1.5"
					d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
				></path>
				<path
					stroke-linecap="round"
					stroke-linejoin="round"
					stroke-width="1.5"
					d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
				></path>
			</svg>
			<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">No media yet</p>
		</div>
	{/if}
</div>

<!-- Edit Modal -->
{#if (selectedPhoto || selectedVideo) && isActive}
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
		role="dialog"
		aria-modal="true"
	>
		<div class="w-full max-w-md rounded-lg bg-white p-6 dark:bg-gray-800">
			<h3 class="mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100">
				Edit {selectedPhoto ? 'Photo' : 'Video'}
			</h3>

			<div class="space-y-4">
				<label class="block">
					<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Title</span>
					<input
						type="text"
						class="mt-1 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-transparent focus:ring-2 focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 {colors.ring}"
						value={editTitle}
						oninput={(e) => (editTitle = e.currentTarget.value)}
						disabled={isUpdating}
					/>
				</label>

				<label class="block">
					<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Notes</span>
					<textarea
						class="mt-1 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 focus:border-transparent focus:ring-2 focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 {colors.ring}"
						rows="3"
						disabled={isUpdating}
						oninput={(e) => (editNotes = e.currentTarget.value)}>{editNotes}</textarea
					>
				</label>

				<label class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
					<input
						type="checkbox"
						class="rounded border-gray-300 text-gray-600 focus:ring-gray-500 dark:border-gray-600 dark:bg-gray-700"
						checked={editInternal}
						onchange={(e) => (editInternal = e.currentTarget.checked)}
						disabled={isUpdating}
					/>
					<span>Internal only</span>
				</label>
			</div>

			<div class="mt-6 flex justify-end gap-2">
				<button
					type="button"
					class="rounded-lg px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
					onclick={closeEditor}
					disabled={isUpdating}
				>
					Cancel
				</button>
				<button
					type="button"
					class="inline-flex items-center gap-1.5 rounded-lg px-4 py-2 text-sm font-medium text-white {colors.bg}"
					onclick={handleUpdateMedia}
					disabled={isUpdating}
				>
					{#if isUpdating}
						<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
							<circle
								class="opacity-25"
								cx="12"
								cy="12"
								r="10"
								stroke="currentColor"
								stroke-width="4"
							></circle>
							<path
								class="opacity-75"
								fill="currentColor"
								d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
							></path>
						</svg>
					{/if}
					<span>Save</span>
				</button>
			</div>
		</div>
	</div>
{/if}
