<script lang="ts">
	import BackButton from '$components/BackButton.svelte'
	import PhotoView from '$components/PhotoView.svelte'
	import PhotoMetadata from '$components/PhotoMetadata.svelte'
	import { generateMetaTags } from '$lib/utils/metadata'
	import { page } from '$app/stores'
	import { goto } from '$app/navigation'
	import { onMount } from 'svelte'
	import { spring } from 'svelte/motion'
	import { getCurrentMousePosition } from '$lib/stores/mouse'
	import type { PageData } from './$types'
	import { isAlbum } from '$lib/types/photos'
	import ArrowLeft from '$icons/arrow-left.svg'
	import ArrowRight from '$icons/arrow-right.svg'

	let { data }: { data: PageData } = $props()

	const photo = $derived(data.photo)
	const error = $derived(data.error)
	const photoItems = $derived(data.photoItems || [])
	const currentPhotoId = $derived(data.currentPhotoId)

	// Hover tracking for arrow buttons
	let isHoveringLeft = $state(false)
	let isHoveringRight = $state(false)

	// Spring stores for smooth button movement
	const leftButtonCoords = spring(
		{ x: 0, y: 0 },
		{
			stiffness: 0.3,
			damping: 0.8
		}
	)

	const rightButtonCoords = spring(
		{ x: 0, y: 0 },
		{
			stiffness: 0.3,
			damping: 0.8
		}
	)

	// Default button positions (will be set once photo loads)
	let defaultLeftX = 0
	let defaultRightX = 0

	const pageUrl = $derived($page.url.href)

	// Generate metadata
	const metaTags = $derived(
		photo
			? generateMetaTags({
					title: photo.title || 'Photo',
					description: photo.description || photo.caption || 'A photograph',
					url: pageUrl,
					image: photo.url,
					titleFormat: { type: 'by' }
				})
			: generateMetaTags({
					title: 'Photo Not Found',
					description: 'The photo you are looking for could not be found.',
					url: pageUrl,
					noindex: true
				})
	)

	// Generate JSON-LD for photo
	const photoJsonLd = $derived(
		photo
			? {
					'@context': 'https://schema.org',
					'@type': 'ImageObject',
					name: photo.title || 'Photo',
					description: photo.description || photo.caption,
					contentUrl: photo.url,
					url: pageUrl,
					dateCreated: photo.createdAt,
					author: {
						'@type': 'Person',
						name: '@jedmund'
					}
				}
			: null
	)

	// Parse EXIF data if available
	const exifData = $derived(
		photo?.exifData && typeof photo.exifData === 'object' ? photo.exifData : null
	)

	// Get previous and next photos (excluding albums)
	const adjacentPhotos = $derived(() => {
		if (!photoItems.length || !currentPhotoId) return { prev: null, next: null }

		// Filter out albums - we only want photos
		const photosOnly = photoItems.filter((item) => !isAlbum(item))
		const currentIndex = photosOnly.findIndex((item) => item.id === currentPhotoId)

		if (currentIndex === -1) return { prev: null, next: null }

		return {
			prev: currentIndex > 0 ? photosOnly[currentIndex - 1] : null,
			next: currentIndex < photosOnly.length - 1 ? photosOnly[currentIndex + 1] : null
		}
	})

	// Handle photo navigation
	function navigateToPhoto(item: any) {
		if (!item) return
		// Extract media ID from item.id (could be 'media-123' or 'photo-123')
		const mediaId = item.id.replace(/^(media|photo)-/, '')
		goto(`/photos/p/${mediaId}`)
	}

	function handleKeydown(e: KeyboardEvent) {
		// Arrow key navigation for photos
		if (e.key === 'ArrowLeft' && adjacentPhotos().prev) {
			navigateToPhoto(adjacentPhotos().prev)
		} else if (e.key === 'ArrowRight' && adjacentPhotos().next) {
			navigateToPhoto(adjacentPhotos().next)
		}
	}

	// Set default button positions when component mounts
	$effect(() => {
		if (!photo) return

		// Wait for DOM to update and image to load
		const checkAndSetPositions = () => {
			const pageContainer = document.querySelector('.photo-page') as HTMLElement
			const photoImage = pageContainer?.querySelector('.photo-content-wrapper img') as HTMLElement

			if (photoImage && photoImage.complete) {
				const imageRect = photoImage.getBoundingClientRect()
				const pageRect = pageContainer.getBoundingClientRect()

				// Calculate default positions relative to the image
				// Add 24px (half button width) since we're using translate(-50%, -50%)
				defaultLeftX = imageRect.left - pageRect.left - 24 - 16 // half button width + gap
				defaultRightX = imageRect.right - pageRect.left + 24 + 16 // half button width + gap

				// Set initial positions at the vertical center of the image
				const centerY = imageRect.top - pageRect.top + imageRect.height / 2
				leftButtonCoords.set({ x: defaultLeftX, y: centerY }, { hard: true })
				rightButtonCoords.set({ x: defaultRightX, y: centerY }, { hard: true })

				// Check if mouse is already in a hover zone
				// Small delay to ensure mouse store is initialized
				setTimeout(() => {
					checkInitialMousePosition(pageContainer, imageRect, pageRect)
				}, 10)
			} else {
				// If image not loaded yet, try again
				setTimeout(checkAndSetPositions, 50)
			}
		}

		checkAndSetPositions()
	})

	// Check mouse position on load
	function checkInitialMousePosition(
		pageContainer: HTMLElement,
		imageRect: DOMRect,
		pageRect: DOMRect
	) {
		// Get current mouse position from store
		const currentPos = getCurrentMousePosition()

		// If no mouse position tracked yet, try to trigger one
		if (currentPos.x === 0 && currentPos.y === 0) {
			// Set up a one-time listener for the first mouse move
			const handleFirstMove = (e: MouseEvent) => {
				const x = e.clientX
				const mouseX = e.clientX - pageRect.left
				const mouseY = e.clientY - pageRect.top

				// Check if mouse is in hover zones
				if (x < imageRect.left) {
					isHoveringLeft = true
					leftButtonCoords.set({ x: mouseX, y: mouseY }, { hard: true })
				} else if (x > imageRect.right) {
					isHoveringRight = true
					rightButtonCoords.set({ x: mouseX, y: mouseY }, { hard: true })
				}

				// Remove the listener
				window.removeEventListener('mousemove', handleFirstMove)
			}

			window.addEventListener('mousemove', handleFirstMove)
			return
		}

		// We have a mouse position, check if it's in a hover zone
		const x = currentPos.x
		const mouseX = currentPos.x - pageRect.left
		const mouseY = currentPos.y - pageRect.top

		// Store client coordinates for scroll updates
		lastClientX = currentPos.x
		lastClientY = currentPos.y

		// Check if mouse is in hover zones
		if (x < imageRect.left) {
			isHoveringLeft = true
			leftButtonCoords.set({ x: mouseX, y: mouseY }, { hard: true })
		} else if (x > imageRect.right) {
			isHoveringRight = true
			rightButtonCoords.set({ x: mouseX, y: mouseY }, { hard: true })
		}
	}

	// Track last known mouse position for scroll updates
	let lastMouseX = 0
	let lastMouseY = 0

	// Store last mouse client position for scroll updates
	let lastClientX = 0
	let lastClientY = 0

	// Update button positions during scroll
	function handleScroll() {
		if (!isHoveringLeft && !isHoveringRight) return

		const pageContainer = document.querySelector('.photo-page') as HTMLElement
		if (!pageContainer) return

		// Use last known mouse position (which is viewport-relative)
		// and recalculate relative to the page container's new position
		const pageRect = pageContainer.getBoundingClientRect()
		const mouseX = lastClientX - pageRect.left
		const mouseY = lastClientY - pageRect.top

		// Update button positions
		if (isHoveringLeft) {
			leftButtonCoords.set({ x: mouseX, y: mouseY })
		}

		if (isHoveringRight) {
			rightButtonCoords.set({ x: mouseX, y: mouseY })
		}
	}

	// Mouse tracking for hover areas
	function handleMouseMove(event: MouseEvent) {
		const pageContainer = event.currentTarget as HTMLElement
		const photoWrapper = pageContainer.querySelector('.photo-content-wrapper') as HTMLElement

		if (!photoWrapper) return

		// Get the actual image element inside PhotoView
		const photoImage = photoWrapper.querySelector('img') as HTMLElement
		if (!photoImage) return

		const pageRect = pageContainer.getBoundingClientRect()
		const photoRect = photoImage.getBoundingClientRect()

		const x = event.clientX
		const mouseX = event.clientX - pageRect.left
		const mouseY = event.clientY - pageRect.top

		// Store last mouse position for scroll updates
		lastClientX = event.clientX
		lastClientY = event.clientY

		// Check if mouse is in the left or right margin (outside the photo)
		const wasHoveringLeft = isHoveringLeft
		const wasHoveringRight = isHoveringRight

		isHoveringLeft = x < photoRect.left
		isHoveringRight = x > photoRect.right

		// Calculate image center Y position
		const imageCenterY = photoRect.top - pageRect.top + photoRect.height / 2

		// Update button positions
		if (isHoveringLeft) {
			leftButtonCoords.set({ x: mouseX, y: mouseY })
		} else if (wasHoveringLeft && !isHoveringLeft) {
			// Reset left button to default
			leftButtonCoords.set({ x: defaultLeftX, y: imageCenterY })
		}

		if (isHoveringRight) {
			rightButtonCoords.set({ x: mouseX, y: mouseY })
		} else if (wasHoveringRight && !isHoveringRight) {
			// Reset right button to default
			rightButtonCoords.set({ x: defaultRightX, y: imageCenterY })
		}
	}

	function handleMouseLeave() {
		isHoveringLeft = false
		isHoveringRight = false

		// Reset buttons to default positions
		const pageContainer = document.querySelector('.photo-page') as HTMLElement
		const photoImage = pageContainer?.querySelector('.photo-content-wrapper img') as HTMLElement

		if (photoImage && pageContainer) {
			const imageRect = photoImage.getBoundingClientRect()
			const pageRect = pageContainer.getBoundingClientRect()
			const centerY = imageRect.top - pageRect.top + imageRect.height / 2

			leftButtonCoords.set({ x: defaultLeftX, y: centerY })
			rightButtonCoords.set({ x: defaultRightX, y: centerY })
		}
	}

	// Set up keyboard and scroll listeners
	$effect(() => {
		window.addEventListener('keydown', handleKeydown)
		window.addEventListener('scroll', handleScroll)

		return () => {
			window.removeEventListener('keydown', handleKeydown)
			window.removeEventListener('scroll', handleScroll)
		}
	})
</script>

<svelte:head>
	<title>{metaTags.title}</title>
	<meta name="description" content={metaTags.description} />

	<!-- OpenGraph -->
	{#each Object.entries(metaTags.openGraph) as [property, content]}
		<meta property="og:{property}" {content} />
	{/each}

	<!-- Twitter Card -->
	{#each Object.entries(metaTags.twitter) as [property, content]}
		<meta name="twitter:{property}" {content} />
	{/each}

	<!-- Canonical URL -->
	<link rel="canonical" href={metaTags.other.canonical} />

	<!-- JSON-LD -->
	{#if photoJsonLd}
		{@html `<script type="application/ld+json">${JSON.stringify(photoJsonLd)}</script>`}
	{/if}
</svelte:head>

{#if error}
	<div class="error-container">
		<div class="error-message">
			<h1>Photo Not Found</h1>
			<p>{error}</p>
			<BackButton href="/photos" label="Back to Photos" />
		</div>
	</div>
{:else if photo}
	<div class="photo-page" onmousemove={handleMouseMove} onmouseleave={handleMouseLeave}>
		<div class="photo-content-wrapper">
			<PhotoView src={photo.url} alt={photo.caption} title={photo.title} id={photo.id} />
		</div>

		<!-- Adjacent Photos Navigation -->
		<div class="adjacent-navigation">
			{#if adjacentPhotos().prev}
				<button
					class="nav-button prev"
					class:hovering={isHoveringLeft}
					style="
						left: {$leftButtonCoords.x}px;
						top: {$leftButtonCoords.y}px;
						transform: translate(-50%, -50%);
					"
					onclick={() => navigateToPhoto(adjacentPhotos().prev)}
					type="button"
					aria-label="Previous photo"
				>
					<ArrowLeft class="nav-icon" />
				</button>
			{/if}

			{#if adjacentPhotos().next}
				<button
					class="nav-button next"
					class:hovering={isHoveringRight}
					style="
						left: {$rightButtonCoords.x}px;
						top: {$rightButtonCoords.y}px;
						transform: translate(-50%, -50%);
					"
					onclick={() => navigateToPhoto(adjacentPhotos().next)}
					type="button"
					aria-label="Next photo"
				>
					<ArrowRight class="nav-icon" />
				</button>
			{/if}
		</div>

		<PhotoMetadata
			title={photo.title}
			caption={photo.caption}
			description={photo.description}
			{exifData}
			createdAt={photo.createdAt}
			backHref={photo.album ? `/photos/${photo.album.slug}` : '/photos'}
			backLabel={photo.album ? `Back to ${photo.album.title}` : 'Back to Photos'}
			showBackButton={true}
		/>
	</div>
{/if}

<style lang="scss">
	@import '$styles/variables.scss';
	@import '$styles/mixins.scss';
	.error-container {
		display: flex;
		justify-content: center;
		align-items: center;
		min-height: 60vh;
		padding: $unit-6x $unit-3x;
	}

	.error-message {
		text-align: center;
		max-width: 500px;

		h1 {
			font-size: 1.75rem;
			font-weight: 600;
			margin: 0 0 $unit-2x;
			color: $red-60;
		}

		p {
			margin: 0 0 $unit-3x;
			color: $grey-40;
			line-height: 1.5;
		}
	}

	.photo-page {
		width: 100%;
		max-width: 1200px;
		margin: 0 auto;
		padding: 0 $unit-3x $unit-4x;
		align-items: center;
		display: flex;
		flex-direction: column;
		gap: $unit-2x;
		box-sizing: border-box;
		position: relative;

		@include breakpoint('tablet') {
			max-width: 900px;
		}

		@include breakpoint('phone') {
			padding: 0 $unit-2x $unit-2x;
			gap: $unit;
		}
	}

	.photo-content-wrapper {
		position: relative;
		max-width: 700px;
		width: 100%;
		margin: 0 auto;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	// Adjacent Navigation
	.adjacent-navigation {
		position: absolute;
		top: 0;
		bottom: 0;
		left: 0;
		right: 0;
		display: flex;
		justify-content: space-between;
		align-items: center;
		pointer-events: none;
		z-index: 100;

		// Hide on mobile and tablet
		@include breakpoint('tablet') {
			display: none;
		}
	}

	.nav-button {
		width: 48px;
		height: 48px;
		pointer-events: auto;
		position: absolute;
		border: none;
		padding: 0;
		background: $grey-100;
		cursor: pointer;
		border-radius: 50%;
		display: flex;
		align-items: center;
		justify-content: center;
		transition:
			background 0.2s ease,
			box-shadow 0.2s ease;

		&:hover {
			background: $grey-95;
		}

		&.hovering {
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

			&:hover {
				box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
			}
		}

		&:focus-visible {
			outline: none;
			box-shadow:
				0 0 0 3px $red-60,
				0 0 0 5px $grey-100;
		}

		:global(svg) {
			stroke: $grey-10;
			width: 16px;
			height: 16px;
			fill: none;
			stroke-width: 2px;
			stroke-linecap: round;
			stroke-linejoin: round;
		}
	}
</style>
