<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { themeColors } from '$lib/stores/theme';
	import '$lib/assets/css/model-viewer.css';
	import * as THREE from 'three';
	import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
	import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
	import Icon from '@iconify/svelte';

	interface Props {
		modelPath: string;
		modelName?: string;
		class?: string;
	}

	let { modelPath, modelName = 'Model', class: className = '' }: Props = $props();

	let container: HTMLDivElement;
	let scene: THREE.Scene;
	let camera: THREE.PerspectiveCamera;
	let renderer: THREE.WebGLRenderer;
	let controls: OrbitControls;
	let model: THREE.Group | null = null;
	let animationId: number;
	let sceneInitialized = false;

	let isLoading = $state(true);
	let loadError = $state<string | null>(null);
	let isFullscreen = $state(false);
	let autoRotate = $state(true);
	let wireframe = $state(false);
	let showGround = $state(true);
	let lightIntensity = $state(1);
	let showControls = $state(false);
	
	let ground: THREE.Mesh | null = null;

	// Watch for modelPath changes
	$effect(() => {
		if (modelPath && sceneInitialized) {
			// Remove old model
			if (model) {
				scene.remove(model);
				model.traverse((child) => {
					if (child instanceof THREE.Mesh) {
						child.geometry.dispose();
						if (Array.isArray(child.material)) {
							child.material.forEach(m => m.dispose());
						} else {
							child.material.dispose();
						}
					}
				});
				model = null;
			}
			isLoading = true;
			loadError = null;
			loadModel();
		}
	});

	function initScene() {
		const width = container.clientWidth;
		const height = container.clientHeight;

		// Scene
		scene = new THREE.Scene();
		scene.background = null; // Transparent background

		// Camera
		camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
		camera.position.set(0, 1, 3);

		// Renderer
		renderer = new THREE.WebGLRenderer({ 
			antialias: true, 
			alpha: true,
			powerPreference: 'high-performance'
		});
		renderer.setSize(width, height);
		renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
		renderer.shadowMap.enabled = true;
		renderer.shadowMap.type = THREE.PCFSoftShadowMap;
		renderer.outputColorSpace = THREE.SRGBColorSpace;
		renderer.toneMapping = THREE.ACESFilmicToneMapping;
		renderer.toneMappingExposure = 1.2;
		container.appendChild(renderer.domElement);

		// Controls
		controls = new OrbitControls(camera, renderer.domElement);
		controls.enableDamping = true;
		controls.dampingFactor = 0.05;
		controls.enablePan = false;
		controls.minDistance = 1;
		controls.maxDistance = 10;
		controls.autoRotate = autoRotate;
		controls.autoRotateSpeed = 2;

		// Lighting
		const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
		scene.add(ambientLight);

		const directionalLight1 = new THREE.DirectionalLight(0xffffff, 1);
		directionalLight1.position.set(5, 5, 5);
		directionalLight1.castShadow = true;
		directionalLight1.userData.baseIntensity = 1;
		scene.add(directionalLight1);

		const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
		directionalLight2.position.set(-5, 3, -5);
		directionalLight2.userData.baseIntensity = 0.5;
		scene.add(directionalLight2);

		// Subtle rim light
		const rimLight = new THREE.DirectionalLight(0x88ccff, 0.3);
		rimLight.position.set(0, 3, -5);
		rimLight.userData.baseIntensity = 0.3;
		scene.add(rimLight);

		// Ground plane (subtle)
		const groundGeometry = new THREE.CircleGeometry(2, 32);
		const groundMaterial = new THREE.MeshStandardMaterial({
			color: 0x222222,
			transparent: true,
			opacity: 0.3
		});
		ground = new THREE.Mesh(groundGeometry, groundMaterial);
		ground.rotation.x = -Math.PI / 2;
		ground.position.y = -0.5;
		ground.receiveShadow = true;
		scene.add(ground);

		sceneInitialized = true;
		loadModel();
	}

	function loadModel() {
		const loader = new GLTFLoader();
		
		loader.load(
			modelPath,
			(gltf) => {
				model = gltf.scene;
				
				// Center and scale the model
				const box = new THREE.Box3().setFromObject(model);
				const center = box.getCenter(new THREE.Vector3());
				const size = box.getSize(new THREE.Vector3());
				
				// Center the model
				model.position.sub(center);
				
				// Scale to fit
				const maxDim = Math.max(size.x, size.y, size.z);
				const scale = 1.5 / maxDim;
				model.scale.setScalar(scale);
				
				// Enable shadows
				model.traverse((child) => {
					if (child instanceof THREE.Mesh) {
						child.castShadow = true;
						child.receiveShadow = true;
					}
				});
				
				scene.add(model);
				isLoading = false;
				
				// Adjust camera based on model
				camera.position.set(0, size.y * scale * 0.5, 2.5);
				controls.target.set(0, 0, 0);
				controls.update();
			},
			(progress) => {
				// Loading progress
			},
			(error) => {
				console.error('Error loading model:', error);
				loadError = 'Failed to load model';
				isLoading = false;
			}
		);
	}

	function animate() {
		animationId = requestAnimationFrame(animate);
		controls.update();
		renderer.render(scene, camera);
	}

	function handleResize() {
		if (!container || !camera || !renderer) return;
		
		const width = container.clientWidth;
		const height = container.clientHeight;
		
		camera.aspect = width / height;
		camera.updateProjectionMatrix();
		renderer.setSize(width, height);
	}

	function toggleAutoRotate() {
		autoRotate = !autoRotate;
		if (controls) {
			controls.autoRotate = autoRotate;
		}
	}

	function toggleFullscreen() {
		isFullscreen = !isFullscreen;
		setTimeout(handleResize, 100);
	}

	function resetCamera() {
		if (!camera || !controls) return;
		camera.position.set(0, 1, 3);
		controls.target.set(0, 0, 0);
		controls.update();
	}

	function toggleWireframe() {
		wireframe = !wireframe;
		if (model) {
			model.traverse((child) => {
				if (child instanceof THREE.Mesh && child.material) {
					if (Array.isArray(child.material)) {
						child.material.forEach(m => m.wireframe = wireframe);
					} else {
						child.material.wireframe = wireframe;
					}
				}
			});
		}
	}

	function toggleGround() {
		showGround = !showGround;
		if (ground) {
			ground.visible = showGround;
		}
	}

	function adjustLighting(delta: number) {
		lightIntensity = Math.max(0.2, Math.min(2, lightIntensity + delta));
		if (scene) {
			scene.traverse((child) => {
				if (child instanceof THREE.DirectionalLight) {
					child.intensity = child.userData.baseIntensity * lightIntensity;
				} else if (child instanceof THREE.AmbientLight) {
					child.intensity = 0.4 * lightIntensity;
				}
			});
		}
	}

	function zoomIn() {
		if (!camera || !controls) return;
		const direction = new THREE.Vector3();
		camera.getWorldDirection(direction);
		camera.position.addScaledVector(direction, 0.5);
		controls.update();
	}

	function zoomOut() {
		if (!camera || !controls) return;
		const direction = new THREE.Vector3();
		camera.getWorldDirection(direction);
		camera.position.addScaledVector(direction, -0.5);
		controls.update();
	}

	function rotateCamera(direction: 'left' | 'right' | 'up' | 'down') {
		if (!controls) return;
		
		const rotateSpeed = 0.1;
		const spherical = new THREE.Spherical();
		const offset = new THREE.Vector3();
		
		// Get current camera position relative to target
		offset.copy(camera.position).sub(controls.target);
		spherical.setFromVector3(offset);
		
		switch (direction) {
			case 'left':
				spherical.theta += rotateSpeed;
				break;
			case 'right':
				spherical.theta -= rotateSpeed;
				break;
			case 'up':
				spherical.phi = Math.max(0.1, spherical.phi - rotateSpeed);
				break;
			case 'down':
				spherical.phi = Math.min(Math.PI - 0.1, spherical.phi + rotateSpeed);
				break;
		}
		
		offset.setFromSpherical(spherical);
		camera.position.copy(controls.target).add(offset);
		controls.update();
	}

	function handleKeydown(event: KeyboardEvent) {
		// Only handle if this component is focused or in fullscreen
		if (!container?.contains(document.activeElement) && !isFullscreen) return;
		
		switch (event.key) {
			case 'ArrowLeft':
				event.preventDefault();
				rotateCamera('left');
				break;
			case 'ArrowRight':
				event.preventDefault();
				rotateCamera('right');
				break;
			case 'ArrowUp':
				event.preventDefault();
				rotateCamera('up');
				break;
			case 'ArrowDown':
				event.preventDefault();
				rotateCamera('down');
				break;
			case 'Escape':
				if (isFullscreen) {
					isFullscreen = false;
					setTimeout(handleResize, 100);
				}
				break;
		}
	}

	function toggleControlsPanel() {
		showControls = !showControls;
	}

	onMount(() => {
		if (container) {
			initScene();
			animate();
			window.addEventListener('resize', handleResize);
			window.addEventListener('keydown', handleKeydown);
		}
	});

	onDestroy(() => {
		if (animationId) {
			cancelAnimationFrame(animationId);
		}
		if (renderer) {
			renderer.dispose();
		}
		window.removeEventListener('resize', handleResize);
		window.removeEventListener('keydown', handleKeydown);
	});
</script>

<div 
	class="model-viewer {className}"
	class:fullscreen={isFullscreen}
	style="
		--viewer-bg: {$themeColors.terminal};
		--viewer-border: {$themeColors.border};
		--viewer-text: {$themeColors.text};
		--viewer-muted: {$themeColors.textMuted};
		--viewer-primary: {$themeColors.primary};
		--viewer-accent: {$themeColors.accent};
	"
>
	<!-- Header -->
	<div class="viewer-header">
		<div class="header-left">
			<Icon icon="mdi:cube-outline" width="16" />
			<span class="model-name">{modelName}</span>
		</div>
		<div class="header-controls">
			<button 
				class="control-btn" 
				title={autoRotate ? 'Stop rotation' : 'Auto rotate'}
				onclick={toggleAutoRotate}
				class:active={autoRotate}
			>
				<Icon icon={autoRotate ? 'mdi:rotate-3d' : 'mdi:rotate-3d-variant'} width="16" />
			</button>
			<button 
				class="control-btn" 
				title="Reset camera"
				onclick={resetCamera}
			>
				<Icon icon="mdi:camera-flip" width="16" />
			</button>
			<button 
				class="control-btn" 
				title="More controls"
				onclick={toggleControlsPanel}
				class:active={showControls}
			>
				<Icon icon="mdi:tune" width="16" />
			</button>
			<button 
				class="control-btn" 
				title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
				onclick={toggleFullscreen}
			>
				<Icon icon={isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'} width="16" />
			</button>
		</div>
	</div>

	<!-- Extended controls panel -->
	{#if showControls}
		<div class="controls-panel">
			<div class="control-group">
				<span class="control-label">View</span>
				<div class="control-buttons">
					<button 
						class="control-btn small" 
						title="Zoom in"
						onclick={zoomIn}
					>
						<Icon icon="mdi:magnify-plus" width="14" />
					</button>
					<button 
						class="control-btn small" 
						title="Zoom out"
						onclick={zoomOut}
					>
						<Icon icon="mdi:magnify-minus" width="14" />
					</button>
				</div>
			</div>
			<div class="control-group">
				<span class="control-label">Lighting</span>
				<div class="control-buttons">
					<button 
						class="control-btn small" 
						title="Decrease brightness"
						onclick={() => adjustLighting(-0.2)}
					>
						<Icon icon="mdi:brightness-5" width="14" />
					</button>
					<span class="control-value">{Math.round(lightIntensity * 100)}%</span>
					<button 
						class="control-btn small" 
						title="Increase brightness"
						onclick={() => adjustLighting(0.2)}
					>
						<Icon icon="mdi:brightness-7" width="14" />
					</button>
				</div>
			</div>
			<div class="control-group">
				<span class="control-label">Display</span>
				<div class="control-buttons">
					<button 
						class="control-btn small" 
						title={wireframe ? 'Solid view' : 'Wireframe view'}
						onclick={toggleWireframe}
						class:active={wireframe}
					>
						<Icon icon={wireframe ? 'mdi:cube' : 'mdi:cube-outline'} width="14" />
					</button>
					<button 
						class="control-btn small" 
						title={showGround ? 'Hide ground' : 'Show ground'}
						onclick={toggleGround}
						class:active={showGround}
					>
						<Icon icon="mdi:checkerboard" width="14" />
					</button>
				</div>
			</div>
		</div>
	{/if}

	<!-- Canvas container -->
	<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
	<div class="canvas-container" bind:this={container} tabindex="0" role="application" aria-label="3D model viewer - use arrow keys to rotate">
		{#if isLoading}
			<div class="loading-overlay">
				<Icon icon="mdi:loading" width="32" class="spin" />
				<span>Loading model...</span>
			</div>
		{/if}
		{#if loadError}
			<div class="error-overlay">
				<Icon icon="mdi:alert-circle" width="32" />
				<span>{loadError}</span>
			</div>
		{/if}
	</div>

	<!-- Footer hints -->
	<div class="viewer-footer">
		<span class="hint">
			<Icon icon="mdi:mouse" width="14" />
			Drag to rotate
		</span>
		<span class="hint">
			<Icon icon="mdi:magnify-plus-minus" width="14" />
			Scroll to zoom
		</span>
		<span class="hint">
			<Icon icon="mdi:arrow-all" width="14" />
			Arrow keys
		</span>
	</div>
</div>
