<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { themeColors } from '$lib/stores/theme';
	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 toggleControlsPanel() {
		showControls = !showControls;
	}

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

	onDestroy(() => {
		if (animationId) {
			cancelAnimationFrame(animationId);
		}
		if (renderer) {
			renderer.dispose();
		}
		window.removeEventListener('resize', handleResize);
	});
</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 -->
	<div class="canvas-container" bind:this={container}>
		{#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>
	</div>
</div>

<style>
	.model-viewer {
		display: flex;
		flex-direction: column;
		background: var(--viewer-bg);
		border: 1px solid var(--viewer-border);
		border-radius: 8px;
		overflow: hidden;
		transition: all 0.3s ease;
	}

	.model-viewer.fullscreen {
		position: fixed;
		inset: 60px 0 0 0;
		z-index: 100;
		border-radius: 0;
		border: none;
	}

	.viewer-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 0.5rem 0.75rem;
		background: color-mix(in srgb, var(--viewer-bg) 80%, black);
		border-bottom: 1px solid var(--viewer-border);
	}

	.header-left {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		color: var(--viewer-primary);
		font-size: 0.85rem;
		font-weight: 500;
	}

	.header-controls {
		display: flex;
		gap: 0.25rem;
	}

	.control-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 28px;
		height: 28px;
		background: transparent;
		border: 1px solid transparent;
		border-radius: 4px;
		color: var(--viewer-muted);
		cursor: pointer;
		transition: all 0.2s ease;
	}

	.control-btn:hover {
		background: var(--viewer-border);
		color: var(--viewer-text);
		border-color: var(--viewer-border);
	}

	.control-btn.active {
		background: var(--viewer-primary);
		color: var(--viewer-bg);
		border-color: var(--viewer-primary);
	}

	.control-btn.small {
		width: 24px;
		height: 24px;
	}

	/* Extended controls panel */
	.controls-panel {
		display: flex;
		flex-wrap: wrap;
		gap: 1rem;
		padding: 0.5rem 0.75rem;
		background: color-mix(in srgb, var(--viewer-bg) 90%, black);
		border-bottom: 1px solid var(--viewer-border);
	}

	.control-group {
		display: flex;
		align-items: center;
		gap: 0.5rem;
	}

	.control-label {
		font-size: 0.7rem;
		color: var(--viewer-muted);
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	.control-buttons {
		display: flex;
		align-items: center;
		gap: 0.25rem;
	}

	.control-value {
		font-size: 0.7rem;
		color: var(--viewer-text);
		min-width: 2.5rem;
		text-align: center;
		font-family: 'JetBrains Mono', monospace;
	}

	.canvas-container {
		flex: 1;
		min-height: 300px;
		position: relative;
		background: radial-gradient(
			circle at center,
			color-mix(in srgb, var(--viewer-primary) 5%, transparent),
			transparent 70%
		);
	}

	.canvas-container :global(canvas) {
		display: block;
	}

	.loading-overlay,
	.error-overlay {
		position: absolute;
		inset: 0;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 0.75rem;
		color: var(--viewer-muted);
		font-size: 0.9rem;
	}

	.error-overlay {
		color: #f38ba8;
	}

	:global(.spin) {
		animation: spin 1s linear infinite;
	}

	@keyframes spin {
		from { transform: rotate(0deg); }
		to { transform: rotate(360deg); }
	}

	.viewer-footer {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 1.5rem;
		padding: 0.5rem;
		background: color-mix(in srgb, var(--viewer-bg) 80%, black);
		border-top: 1px solid var(--viewer-border);
	}

	.hint {
		display: flex;
		align-items: center;
		gap: 0.35rem;
		color: var(--viewer-muted);
		font-size: 0.75rem;
	}
</style>
