<script lang="ts">
	import type { SessionPhoto, SessionVideo } from './types';
	import { getAuthenticatedImageUrl } from './types';
	import { SvelteMap, SvelteSet } from 'svelte/reactivity';
	import IconSpinner from '$lib/components/icons/IconSpinner.svelte';
	interface StagedPhoto {
		id: string;
		file: File;
		previewUrl: string;
		title: string;
		notes: string;
		internal: boolean;
		uploading: boolean;
		error?: string;
	}

	interface Props {
		photos: SessionPhoto[];
		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>;
	}

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

	// Store authenticated URLs
	let authenticatedImageUrls = new SvelteMap<string, string>();

	// Track URLs that are currently being fetched to prevent duplicates
	let fetchingUrls = new SvelteSet<string>();

	// Load authenticated image URLs when photos/videos change
	$effect(() => {
		// Load photo URLs (both thumbnail and full image)
		photos?.forEach(async (photo) => {
			// Fetch thumbnail URL
			const thumbnailUrl = photo.thumbnail?.url || photo.image.url;
			if (
				thumbnailUrl &&
				!authenticatedImageUrls.has(thumbnailUrl) &&
				!fetchingUrls.has(thumbnailUrl)
			) {
				fetchingUrls.add(thumbnailUrl);
				const authUrl = await getAuthenticatedImageUrl(thumbnailUrl);
				authenticatedImageUrls.set(thumbnailUrl, authUrl);
				fetchingUrls.delete(thumbnailUrl);
			}
			// Also fetch full image URL if different from thumbnail
			if (
				photo.image.url !== thumbnailUrl &&
				!authenticatedImageUrls.has(photo.image.url) &&
				!fetchingUrls.has(photo.image.url)
			) {
				fetchingUrls.add(photo.image.url);
				const authUrl = await getAuthenticatedImageUrl(photo.image.url);
				authenticatedImageUrls.set(photo.image.url, authUrl);
				fetchingUrls.delete(photo.image.url);
			}
		});

		// Load video thumbnail URLs and video URLs
		videos?.forEach(async (video) => {
			// Fetch thumbnail
			if (
				video.thumbnail?.url &&
				!authenticatedImageUrls.has(video.thumbnail.url) &&
				!fetchingUrls.has(video.thumbnail.url)
			) {
				fetchingUrls.add(video.thumbnail.url);
				const authUrl = await getAuthenticatedImageUrl(video.thumbnail.url);
				authenticatedImageUrls.set(video.thumbnail.url, authUrl);
				fetchingUrls.delete(video.thumbnail.url);
			}
			// Fetch video URL
			if (
				video.video?.url &&
				!authenticatedImageUrls.has(video.video.url) &&
				!fetchingUrls.has(video.video.url)
			) {
				fetchingUrls.add(video.video.url);
				const authUrl = await getAuthenticatedImageUrl(video.video.url);
				authenticatedImageUrls.set(video.video.url, authUrl);
				fetchingUrls.delete(video.video.url);
			}
		});
	});

	// Open media in new tab
	function openInNewTab(url: string | undefined) {
		if (!url) return;
		const authUrl = authenticatedImageUrls.get(url);
		if (authUrl) {
			window.open(authUrl, '_blank');
		}
	}

	// Upload form state
	let showUploadForm = $state(false);
	let uploadType = $state<'photo' | 'video'>('photo');
	let isUploading = $state(false);

	// Bulk photo upload state
	let stagedPhotos = $state<StagedPhoto[]>([]);
	let defaultInternal = $state(true);
	let isConvertingPhotos = $state(false);
	let uploadProgress = $state<{ completed: number; total: number; failed: number } | null>(null);

	// Single video upload state (videos stay single-file)
	let uploadVideoFile = $state<File | null>(null);
	let uploadVideoTitle = $state('');
	let uploadVideoNotes = $state('');
	let uploadVideoInternal = $state(true);
	let uploadVideoPreviewUrl = $state<string | null>(null);

	// Edit state
	let editingId = $state<string | null>(null);
	let editTitle = $state('');
	let editNotes = $state('');
	let editInternal = $state(false);
	let isEditing = $state(false);

	// Delete state
	let deletingPhotoId = $state<string | null>(null);
	let deletingVideoId = $state<string | null>(null);

	function openUploadForm(type: 'photo' | 'video') {
		uploadType = type;
		showUploadForm = true;
		if (type === 'video') {
			uploadVideoFile = null;
			uploadVideoTitle = '';
			uploadVideoNotes = '';
			uploadVideoInternal = true;
		}
		// Photos: stagedPhotos persists, user can add more
	}

	function closeUploadForm() {
		showUploadForm = false;
		// Clear staged photos and revoke URLs
		for (const photo of stagedPhotos) {
			URL.revokeObjectURL(photo.previewUrl);
		}
		stagedPhotos = [];
		// Clear video state
		if (uploadVideoPreviewUrl) {
			URL.revokeObjectURL(uploadVideoPreviewUrl);
			uploadVideoPreviewUrl = null;
		}
		uploadVideoFile = null;
		uploadVideoTitle = '';
		uploadVideoNotes = '';
	}

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

	function updateStagedPhoto(
		id: string,
		field: 'title' | 'notes' | 'internal',
		value: string | boolean
	) {
		stagedPhotos = stagedPhotos.map((p) => (p.id === id ? { ...p, [field]: value } : p));
	}

	function clearAllStaged() {
		for (const photo of stagedPhotos) {
			URL.revokeObjectURL(photo.previewUrl);
		}
		stagedPhotos = [];
	}

	async function handleUpload() {
		if (uploadType === 'photo') {
			await handleBulkPhotoUpload();
		} else {
			await handleVideoUpload();
		}
	}

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

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

		// Upload in chunks of 2 to avoid overwhelming mobile connections
		const CHUNK_SIZE = 2;
		const photosToUpload = [...stagedPhotos];

		for (let i = 0; i < photosToUpload.length; i += CHUNK_SIZE) {
			const chunk = photosToUpload.slice(i, i + CHUNK_SIZE);

			// Mark chunk as uploading
			const chunkIds = new Set(chunk.map((p) => p.id));
			stagedPhotos = stagedPhotos.map((p) =>
				chunkIds.has(p.id) ? { ...p, uploading: true, error: undefined } : p
			);

			// Upload chunk in parallel
			const chunkResults = await Promise.allSettled(
				chunk.map(async (photo) => {
					try {
						await onUploadPhoto(
							photo.file,
							photo.title || photo.file.name,
							photo.notes,
							photo.internal
						);
						// Remove successful upload
						URL.revokeObjectURL(photo.previewUrl);
						stagedPhotos = stagedPhotos.filter((p) => p.id !== photo.id);
						uploadProgress = {
							...uploadProgress!,
							completed: uploadProgress!.completed + 1
						};
						return { id: photo.id, success: true };
					} 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
						};
						return { id: photo.id, success: false, error: err };
					}
				})
			);
		}

		isUploading = false;
		uploadProgress = null;

		// Close form if all succeeded
		if (stagedPhotos.length === 0) {
			closeUploadForm();
		}
	}

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

		isUploading = true;
		try {
			await onUploadVideo(
				uploadVideoFile,
				uploadVideoTitle || uploadVideoFile.name,
				uploadVideoNotes,
				uploadVideoInternal
			);
			closeUploadForm();
		} catch (err) {
			const errorMessage = err instanceof Error ? err.message : 'Upload failed';
			console.error('Upload failed:', err);
			alert(`Video upload failed: ${errorMessage}`);
		} finally {
			isUploading = false;
		}
	}

	function startEdit(id: string, title: string, notes: string, internal: boolean) {
		editingId = id;
		editTitle = title;
		editNotes = notes;
		editInternal = internal;
	}

	function cancelEdit() {
		editingId = null;
		editTitle = '';
		editNotes = '';
		editInternal = false;
	}

	async function savePhotoEdit(photoId: string) {
		if (!onUpdatePhoto) return;
		isEditing = true;
		try {
			await onUpdatePhoto(photoId, editTitle, editNotes, editInternal);
			cancelEdit();
		} catch (err) {
			console.error('Failed to update photo:', err);
		} finally {
			isEditing = false;
		}
	}

	async function saveVideoEdit(videoId: string) {
		if (!onUpdateVideo) return;
		isEditing = true;
		try {
			await onUpdateVideo(videoId, editTitle, editNotes, editInternal);
			cancelEdit();
		} catch (err) {
			console.error('Failed to update video:', err);
		} finally {
			isEditing = false;
		}
	}

	async function handleDeletePhoto(photoId: string) {
		if (!onDeletePhoto || !confirm('Are you sure you want to delete this photo?')) return;
		deletingPhotoId = photoId;
		try {
			await onDeletePhoto(photoId);
		} catch (err) {
			console.error('Failed to delete photo:', err);
		} finally {
			deletingPhotoId = null;
		}
	}

	async function handleDeleteVideo(videoId: string) {
		if (!onDeleteVideo || !confirm('Are you sure you want to delete this video?')) return;
		deletingVideoId = videoId;
		try {
			await onDeleteVideo(videoId);
		} catch (err) {
			console.error('Failed to delete video:', err);
		} finally {
			deletingVideoId = null;
		}
	}

	// Helper function to create preview URL with HEIC support
	async function createPreviewUrl(file: File): Promise<string> {
		// Check if file is HEIC by extension or MIME type
		const isHeic =
			file.name.toLowerCase().endsWith('.heic') ||
			file.name.toLowerCase().endsWith('.heif') ||
			file.type === 'image/heic' ||
			file.type === 'image/heif';

		if (isHeic) {
			try {
				// Dynamic import - only loads in browser to avoid SSR crash
				const heic2any = (await import('heic2any')).default;
				// Convert HEIC to JPEG for browser preview
				const convertedBlob = await heic2any({
					blob: file,
					toType: 'image/jpeg',
					quality: 0.8
				});
				// heic2any can return Blob or Blob[], handle both
				const blob = Array.isArray(convertedBlob) ? convertedBlob[0] : convertedBlob;
				return URL.createObjectURL(blob);
			} catch (err) {
				console.error('Failed to convert HEIC for preview:', err);
				// Fallback: try regular blob URL (won't work but won't crash)
				return URL.createObjectURL(file);
			}
		}

		// Not HEIC, use regular blob URL
		return URL.createObjectURL(file);
	}

	async function handlePhotoFileChange(event: Event) {
		const target = event.target as HTMLInputElement;
		if (target.files && target.files.length > 0) {
			const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB limit for mobile compatibility
			const validFiles: File[] = [];
			const rejectedFiles: string[] = [];

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

			// Show warning if any files were rejected
			if (rejectedFiles.length > 0) {
				alert(
					`The following files are too large and were not added:\n\n${rejectedFiles.join('\n')}\n\nPlease use smaller images or compress them before uploading.`
				);
			}

			// Stage valid files (async to handle HEIC conversion)
			if (validFiles.length > 0) {
				isConvertingPhotos = true;
				try {
					const newPhotos: StagedPhoto[] = await Promise.all(
						validFiles.map(async (file) => ({
							id: crypto.randomUUID(),
							file,
							previewUrl: await createPreviewUrl(file),
							title: file.name.replace(/\.[^/.]+$/, ''),
							notes: '',
							internal: defaultInternal,
							uploading: false
						}))
					);
					stagedPhotos = [...stagedPhotos, ...newPhotos];
				} finally {
					isConvertingPhotos = false;
				}
			}

			// Reset input so same files can be selected again
			target.value = '';
		}
	}

	function handleVideoFileChange(event: Event) {
		const target = event.target as HTMLInputElement;
		if (target.files && target.files[0]) {
			const file = target.files[0];
			const MAX_VIDEO_SIZE = 50 * 1024 * 1024; // 50MB limit for videos

			// Validate file size
			if (file.size > MAX_VIDEO_SIZE) {
				const sizeMB = (file.size / (1024 * 1024)).toFixed(1);
				alert(
					`Video file is too large (${sizeMB}MB).\n\nMaximum video size is 50MB. Please compress the video or use a shorter clip.`
				);
				target.value = '';
				return;
			}

			uploadVideoFile = file;
			if (!uploadVideoTitle) {
				uploadVideoTitle = uploadVideoFile.name.replace(/\.[^/.]+$/, '');
			}
			// Create preview URL for local file
			if (uploadVideoPreviewUrl) {
				URL.revokeObjectURL(uploadVideoPreviewUrl);
			}
			uploadVideoPreviewUrl = URL.createObjectURL(uploadVideoFile);
		}
	}

	// Helper functions for inline event handlers (TypeScript casting doesn't work in templates)
	function handleStagedTitleInput(id: string, event: Event) {
		const target = event.target as HTMLInputElement;
		updateStagedPhoto(id, 'title', target.value);
	}

	function handleStagedNotesInput(id: string, event: Event) {
		const target = event.target as HTMLTextAreaElement;
		updateStagedPhoto(id, 'notes', target.value);
	}

	function handleStagedInternalChange(id: string, event: Event) {
		const target = event.target as HTMLInputElement;
		updateStagedPhoto(id, 'internal', target.checked);
	}
</script>

<div class="space-y-6">
	<!-- Upload Buttons -->
	{#if isActive}
		<div class="flex gap-3">
			<button
				type="button"
				onclick={() => openUploadForm('photo')}
				class="flex flex-1 items-center justify-center gap-2 rounded-lg border-2 border-dashed border-theme p-4 text-theme-muted transition-colors hover:border-primary-500 hover:text-primary-500"
			>
				<svg class="h-5 w-5" style="fill: none" stroke="currentColor" viewBox="0 0 24 24">
					<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"
					/>
				</svg>
				Add Photos
			</button>
			<button
				type="button"
				onclick={() => openUploadForm('video')}
				class="flex flex-1 items-center justify-center gap-2 rounded-lg border-2 border-dashed border-theme p-4 text-theme-muted transition-colors hover:border-primary-500 hover:text-primary-500"
			>
				<svg class="h-5 w-5" style="fill: none" stroke="currentColor" viewBox="0 0 24 24">
					<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"
					/>
				</svg>
				Add Video
			</button>
		</div>
	{/if}

	<!-- Upload Form Modal -->
	{#if showUploadForm}
		<div class="card-padded border-2 border-primary-500/30 bg-primary-500/5">
			<h3 class="mb-4 font-medium text-theme">
				Upload {uploadType === 'photo' ? 'Photos' : 'Video'}
			</h3>

			{#if uploadType === 'photo'}
				<!-- Bulk Photo Upload -->
				<div class="space-y-4">
					<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
						<input
							id="upload-photos"
							type="file"
							accept="image/*"
							multiple
							onchange={handlePhotoFileChange}
							class="block w-full text-sm text-theme file:mr-4 file:rounded-lg file:border-0 file:bg-primary-500/10 file:px-4 file:py-2 file:text-sm file:font-medium file:text-primary-600 hover:file:bg-primary-500/20 sm:w-auto"
						/>
						<label class="flex items-center gap-2">
							<input
								type="checkbox"
								bind:checked={defaultInternal}
								class="h-4 w-4 rounded border-input text-primary-600 focus:ring-primary-500"
							/>
							<span class="text-sm text-theme">Internal by default</span>
						</label>
					</div>

					<!-- Converting Photos Indicator -->
					{#if isConvertingPhotos}
						<div class="flex items-center justify-center gap-3 rounded-lg border border-theme bg-theme-card p-4">
							<IconSpinner class="h-5 w-5 text-primary-500" />
							<span class="text-sm text-theme">Converting images for preview...</span>
						</div>
					{/if}

					<!-- Staged Photos Grid -->
					{#if stagedPhotos.length > 0}
						<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
							{#each stagedPhotos as photo (photo.id)}
								<div
									class="space-y-3 rounded-lg border border-theme bg-theme-card p-3 {photo.error
										? 'border-red-500'
										: ''}"
								>
									<!-- Thumbnail and remove button -->
									<div class="flex items-start justify-between gap-2">
										<img
											src={photo.previewUrl}
											alt={photo.title}
											class="h-20 w-20 shrink-0 rounded object-cover"
										/>
										<button
											type="button"
											onclick={() => removeStagedPhoto(photo.id)}
											disabled={photo.uploading}
											class="shrink-0 rounded p-1 text-theme-muted hover:bg-black/5 hover:text-red-500 disabled:opacity-50 dark:hover:bg-white/10"
											aria-label="Remove photo"
										>
											{#if photo.uploading}
												<IconSpinner class="h-5 w-5" />
											{:else}
												<svg
													class="h-5 w-5"
													style="fill: none"
													stroke="currentColor"
													viewBox="0 0 24 24"
												>
													<path
														stroke-linecap="round"
														stroke-linejoin="round"
														stroke-width="2"
														d="M6 18L18 6M6 6l12 12"
													/>
												</svg>
											{/if}
										</button>
									</div>

									<!-- Title -->
									<input
										type="text"
										value={photo.title}
										oninput={(e) => handleStagedTitleInput(photo.id, e)}
										placeholder="Title..."
										disabled={photo.uploading}
										class="w-full rounded border border-theme bg-theme px-2 py-1 text-sm text-theme placeholder:text-theme-muted focus:border-primary-500 focus:outline-none disabled:opacity-50"
									/>

									<!-- Notes -->
									<textarea
										oninput={(e) => handleStagedNotesInput(photo.id, e)}
										placeholder="Notes..."
										rows="2"
										disabled={photo.uploading}
										class="w-full rounded border border-theme bg-theme px-2 py-1 text-sm text-theme placeholder:text-theme-muted focus:border-primary-500 focus:outline-none disabled:opacity-50"
										>{photo.notes}</textarea
									>

									<!-- Internal checkbox and error -->
									<div class="flex items-center justify-between">
										<label class="flex items-center gap-2">
											<input
												type="checkbox"
												checked={photo.internal}
												onchange={(e) => handleStagedInternalChange(photo.id, e)}
												disabled={photo.uploading}
												class="h-4 w-4 rounded border-input text-primary-600 focus:ring-primary-500 disabled:opacity-50"
											/>
											<span class="text-xs text-theme-muted">Internal</span>
										</label>
										{#if photo.error}
											<span class="text-xs text-red-500">{photo.error}</span>
										{/if}
									</div>
								</div>
							{/each}
						</div>
					{/if}

					<!-- Upload Progress Indicator -->
					{#if uploadProgress}
						<div class="rounded-lg border border-primary-500/30 bg-primary-500/5 p-4">
							<div class="mb-2 flex items-center justify-between text-sm">
								<span class="font-medium text-theme">
									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 bg-primary-500 transition-all duration-300"
									style="width: {(uploadProgress.completed / uploadProgress.total) * 100}%"
								></div>
							</div>
						</div>
					{/if}

					<!-- Action buttons -->
					<div class="flex flex-col gap-2 sm:flex-row sm:justify-between">
						<button
							type="button"
							onclick={closeUploadForm}
							disabled={isUploading}
							class="btn-ghost disabled:opacity-50"
						>
							Cancel
						</button>
						<div class="flex gap-2">
							{#if stagedPhotos.length > 1 && !isUploading}
								<button
									type="button"
									onclick={clearAllStaged}
									class="btn-ghost text-red-500 hover:text-red-600"
								>
									Clear All
								</button>
							{/if}
							<button
								type="button"
								onclick={handleUpload}
								disabled={stagedPhotos.length === 0 || isUploading}
								class="btn-primary disabled:opacity-50"
							>
								{isUploading
									? 'Uploading...'
									: `Upload ${stagedPhotos.length} Photo${stagedPhotos.length !== 1 ? 's' : ''}`}
							</button>
						</div>
					</div>
				</div>
			{:else}
				<!-- Single Video Upload -->
				<div class="space-y-4">
					<div>
						<label for="upload-video" class="mb-1 block text-sm font-medium text-theme">File</label>
						<input
							id="upload-video"
							type="file"
							accept="video/*"
							onchange={handleVideoFileChange}
							class="block w-full text-sm text-theme file:mr-4 file:rounded-lg file:border-0 file:bg-primary-500/10 file:px-4 file:py-2 file:text-sm file:font-medium file:text-primary-600 hover:file:bg-primary-500/20"
						/>
						{#if uploadVideoPreviewUrl}
							<div class="mt-3 overflow-hidden rounded-lg bg-theme-secondary">
								<!-- svelte-ignore a11y_media_has_caption -->
								<video src={uploadVideoPreviewUrl} class="max-h-48 w-full object-contain" controls
								></video>
							</div>
						{/if}
					</div>

					<div>
						<label for="upload-video-title" class="mb-1 block text-sm font-medium text-theme"
							>Title</label
						>
						<input
							id="upload-video-title"
							type="text"
							bind:value={uploadVideoTitle}
							placeholder="Enter a title..."
							class="w-full rounded-lg border border-theme bg-theme-card px-3 py-2 text-theme placeholder:text-theme-muted focus:border-primary-500 focus:ring-1 focus:ring-primary-500 focus:outline-none"
						/>
					</div>

					<div>
						<label for="upload-video-notes" class="mb-1 block text-sm font-medium text-theme"
							>Notes</label
						>
						<textarea
							id="upload-video-notes"
							bind:value={uploadVideoNotes}
							placeholder="Add notes..."
							rows="2"
							class="w-full rounded-lg border border-theme bg-theme-card px-3 py-2 text-theme placeholder:text-theme-muted focus:border-primary-500 focus:ring-1 focus:ring-primary-500 focus:outline-none"
						></textarea>
					</div>

					<label class="flex items-center gap-2">
						<input
							type="checkbox"
							bind:checked={uploadVideoInternal}
							class="h-4 w-4 rounded border-input text-primary-600 focus:ring-primary-500"
						/>
						<span class="text-sm text-theme">Internal only (not visible to customer)</span>
					</label>

					<div class="flex gap-3">
						<button
							type="button"
							onclick={closeUploadForm}
							disabled={isUploading}
							class="btn-ghost flex-1 disabled:opacity-50"
						>
							Cancel
						</button>
						<button
							type="button"
							onclick={handleUpload}
							disabled={!uploadVideoFile || isUploading}
							class="btn-primary flex-1 disabled:opacity-50"
						>
							{isUploading ? 'Uploading...' : 'Upload'}
						</button>
					</div>
				</div>
			{/if}
		</div>
	{/if}

	<!-- Photos Grid -->
	{#if photos.length > 0}
		<div class="card-padded">
			<h3 class="mb-4 font-medium text-theme">Photos ({photos.length})</h3>
			<div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
				{#each photos as photo (photo.id)}
					{@const thumbnailUrl = photo.thumbnail?.url || photo.image.url}
					<div class="group relative overflow-hidden rounded-lg bg-theme-secondary">
						<button
							type="button"
							onclick={() => openInNewTab(photo.image.url)}
							class="w-full cursor-pointer focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 focus:outline-none"
							aria-label="Open {photo.title || 'photo'} in new tab"
						>
							{#if thumbnailUrl && authenticatedImageUrls.has(thumbnailUrl)}
								<img
									src={authenticatedImageUrls.get(thumbnailUrl)}
									alt={photo.title || 'Photo'}
									class="aspect-square w-full object-cover"
								/>
							{:else if thumbnailUrl}
								<!-- Loading placeholder while fetching authenticated URL -->
								<span
									class="flex aspect-square w-full items-center justify-center bg-theme-secondary"
								>
									<span class="h-8 w-8 animate-pulse rounded-full bg-gray-300 dark:bg-gray-600"
									></span>
								</span>
							{:else}
								<span
									class="flex aspect-square w-full items-center justify-center text-theme-muted"
								>
									<svg
										class="h-12 w-12"
										style="fill: none"
										stroke="currentColor"
										viewBox="0 0 24 24"
									>
										<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"
										/>
									</svg>
								</span>
							{/if}
						</button>

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

						{#if isActive}
							<div
								class="absolute top-2 right-2 flex gap-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
							>
								<button
									type="button"
									onclick={(e) => {
										e.stopPropagation();
										startEdit(photo.id, photo.title || '', photo.notes || '', photo.internal);
									}}
									class="rounded bg-white/90 p-1.5 text-gray-600 hover:text-primary-500 dark:bg-gray-800/90 dark:text-gray-300"
									aria-label="Edit photo"
								>
									<svg class="h-4 w-4" style="fill: none" stroke="currentColor" viewBox="0 0 24 24">
										<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"
										/>
									</svg>
								</button>
								<button
									type="button"
									onclick={(e) => {
										e.stopPropagation();
										handleDeletePhoto(photo.id);
									}}
									disabled={deletingPhotoId === photo.id}
									class="rounded bg-white/90 p-1.5 text-gray-600 hover:text-red-500 disabled:opacity-50 dark:bg-gray-800/90 dark:text-gray-300"
									aria-label="Delete photo"
								>
									{#if deletingPhotoId === photo.id}
										<IconSpinner class="h-4 w-4" />
									{:else}
										<svg
											class="h-4 w-4"
											style="fill: none"
											stroke="currentColor"
											viewBox="0 0 24 24"
										>
											<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"
											/>
										</svg>
									{/if}
								</button>
							</div>
						{/if}

						<div
							class="absolute right-0 bottom-0 left-0 bg-linear-to-t from-black/70 to-transparent p-2"
						>
							<p class="truncate text-xs 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(
									'uploadedByTeamProfileId' in photo ? photo.uploadedByTeamProfileId : null
								)}
							</p>
						</div>
					</div>
				{/each}
			</div>
		</div>
	{/if}

	<!-- Videos Grid -->
	{#if videos.length > 0}
		<div class="card-padded">
			<h3 class="mb-4 font-medium text-theme">Videos ({videos.length})</h3>
			<div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
				{#each videos as video (video.id)}
					<div class="group relative overflow-hidden rounded-lg bg-theme-secondary">
						<button
							type="button"
							onclick={() => openInNewTab(video.video?.url)}
							class="w-full cursor-pointer focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 focus:outline-none"
							aria-label="Open {video.title || 'video'} in new tab"
						>
							{#if video.thumbnail?.url && authenticatedImageUrls.has(video.thumbnail.url)}
								<img
									src={authenticatedImageUrls.get(video.thumbnail.url)}
									alt={video.title || 'Video'}
									class="aspect-video w-full object-cover"
								/>
							{:else if video.thumbnail?.url}
								<!-- Loading placeholder while fetching authenticated URL -->
								<span
									class="flex aspect-video w-full items-center justify-center bg-theme-secondary"
								>
									<span class="h-8 w-8 animate-pulse rounded-full bg-gray-300 dark:bg-gray-600"
									></span>
								</span>
							{:else}
								<span class="flex aspect-video w-full items-center justify-center text-theme-muted">
									<svg
										class="h-12 w-12"
										style="fill: none"
										stroke="currentColor"
										viewBox="0 0 24 24"
									>
										<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"
										/>
									</svg>
								</span>
							{/if}

							<!-- Play icon overlay -->
							<span class="pointer-events-none absolute inset-0 flex items-center justify-center">
								<span class="rounded-full bg-black/50 p-3">
									<svg class="h-6 w-6 text-white" style="fill: currentColor" viewBox="0 0 24 24">
										<path d="M8 5v14l11-7z" />
									</svg>
								</span>
							</span>
						</button>

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

						{#if isActive}
							<div
								class="absolute top-2 right-2 flex gap-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
							>
								<button
									type="button"
									onclick={(e) => {
										e.stopPropagation();
										startEdit(video.id, video.title || '', video.notes || '', video.internal);
									}}
									class="rounded bg-white/90 p-1.5 text-gray-600 hover:text-primary-500 dark:bg-gray-800/90 dark:text-gray-300"
									aria-label="Edit video"
								>
									<svg class="h-4 w-4" style="fill: none" stroke="currentColor" viewBox="0 0 24 24">
										<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"
										/>
									</svg>
								</button>
								<button
									type="button"
									onclick={(e) => {
										e.stopPropagation();
										handleDeleteVideo(video.id);
									}}
									disabled={deletingVideoId === video.id}
									class="rounded bg-white/90 p-1.5 text-gray-600 hover:text-red-500 disabled:opacity-50 dark:bg-gray-800/90 dark:text-gray-300"
									aria-label="Delete video"
								>
									{#if deletingVideoId === video.id}
										<IconSpinner class="h-4 w-4" />
									{:else}
										<svg
											class="h-4 w-4"
											style="fill: none"
											stroke="currentColor"
											viewBox="0 0 24 24"
										>
											<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"
											/>
										</svg>
									{/if}
								</button>
							</div>
						{/if}

						<div
							class="absolute right-0 bottom-0 left-0 bg-linear-to-t from-black/70 to-transparent p-2"
						>
							<p class="truncate text-xs 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.uploadedByTeamProfileId)}
							</p>
						</div>
					</div>
				{/each}
			</div>
		</div>
	{/if}

	<!-- Empty State -->
	{#if photos.length === 0 && videos.length === 0}
		<div class="empty-state">
			<svg class="empty-state-icon" style="fill: none" stroke="currentColor" viewBox="0 0 24 24">
				<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"
				/>
			</svg>
			<h2 class="empty-state-title">No Media Yet</h2>
			<p class="empty-state-text">
				{#if isActive}
					Add photos and videos to document your work.
				{:else}
					No photos or videos were added to this session.
				{/if}
			</p>
		</div>
	{/if}
</div>

<!-- Edit Modal -->
{#if editingId}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
		<div class="w-full max-w-md rounded-xl bg-theme-card p-6 shadow-xl">
			<h3 class="mb-4 font-medium text-theme">Edit Details</h3>

			<div class="space-y-4">
				<div>
					<label for="edit-title" class="mb-1 block text-sm font-medium text-theme">Title</label>
					<input
						id="edit-title"
						type="text"
						bind:value={editTitle}
						class="w-full rounded-lg border border-theme bg-theme px-3 py-2 text-theme focus:border-primary-500 focus:ring-1 focus:ring-primary-500 focus:outline-none"
					/>
				</div>

				<div>
					<label for="edit-notes" class="mb-1 block text-sm font-medium text-theme">Notes</label>
					<textarea
						id="edit-notes"
						bind:value={editNotes}
						rows="3"
						class="w-full rounded-lg border border-theme bg-theme px-3 py-2 text-theme focus:border-primary-500 focus:ring-1 focus:ring-primary-500 focus:outline-none"
					></textarea>
				</div>

				<label class="flex items-center gap-2">
					<input
						type="checkbox"
						bind:checked={editInternal}
						class="h-4 w-4 rounded border-input text-primary-600 focus:ring-primary-500"
					/>
					<span class="text-sm text-theme">Internal only (not visible to customer)</span>
				</label>

				<div class="flex gap-3">
					<button type="button" onclick={cancelEdit} class="btn-ghost flex-1"> Cancel </button>
					<button
						type="button"
						onclick={() => {
							if (!editingId) return;
							const photo = photos.find((p) => p.id === editingId);
							if (photo) {
								savePhotoEdit(editingId);
							} else {
								saveVideoEdit(editingId);
							}
						}}
						disabled={isEditing}
						class="btn-primary flex-1 disabled:opacity-50"
					>
						{isEditing ? 'Saving...' : 'Save'}
					</button>
				</div>
			</div>
		</div>
	</div>
{/if}
