<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref, watch } from 'vue';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

const props = defineProps<{
  modelPath: string;
  canvasTexture?: HTMLCanvasElement | null;
}>();

const containerRef = ref<HTMLDivElement | null>(null);

let scene: THREE.Scene;
let camera: THREE.PerspectiveCamera;
let renderer: THREE.WebGLRenderer;
let controls: OrbitControls;
let model: THREE.Object3D | null = null;
let jerseyMaterial: THREE.MeshStandardMaterial | null = null;
let animationFrameId: number;

const setupScene = () => {
  if (!containerRef.value) return;

  // Scene
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x1e293b);

  // Camera
  camera = new THREE.PerspectiveCamera(
    45,
    containerRef.value.clientWidth / containerRef.value.clientHeight,
    0.1,
    1000
  );
  camera.position.set(0, 1.5, 3);

  // Renderer
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(containerRef.value.clientWidth, containerRef.value.clientHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.shadowMap.enabled = true;
  containerRef.value.appendChild(renderer.domElement);

  // Controls
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.autoRotate = true;
  controls.autoRotateSpeed = 2;

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

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

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

  // Load model
  loadModel();

  // Animation loop
  const animate = () => {
    animationFrameId = requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  };
  animate();

  // Handle resize
  window.addEventListener('resize', handleResize);
};

const handleResize = () => {
  if (!containerRef.value) return;
  
  camera.aspect = containerRef.value.clientWidth / containerRef.value.clientHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(containerRef.value.clientWidth, containerRef.value.clientHeight);
};

const loadModel = () => {
  const loader = new GLTFLoader();
  
  loader.load(
    props.modelPath,
    (gltf) => {
      model = gltf.scene;
      
      // Find the mesh that should receive the texture
      model.traverse((child) => {
        if ((child as THREE.Mesh).isMesh) {
          const mesh = child as THREE.Mesh;
          
          // Create a material for the jersey surface
          jerseyMaterial = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            roughness: 0.7,
            metalness: 0.1,
          });
          
          mesh.material = jerseyMaterial;
          mesh.castShadow = true;
          mesh.receiveShadow = true;
          
          // Apply initial texture if provided
          if (props.canvasTexture) {
            updateTexture(props.canvasTexture);
          }
        }
      });
      
      scene.add(model);
      
      // Center and scale model
      const box = new THREE.Box3().setFromObject(model);
      const center = box.getCenter(new THREE.Vector3());
      model.position.sub(center);
      
      const size = box.getSize(new THREE.Vector3());
      const maxDim = Math.max(size.x, size.y, size.z);
      const scale = 2 / maxDim;
      model.scale.multiplyScalar(scale);
    },
    undefined,
    (error) => {
      console.error('Error loading model:', error);
    }
  );
};

const updateTexture = (canvas: HTMLCanvasElement) => {
  if (!jerseyMaterial) return;
  
  // Create texture from canvas
  const texture = new THREE.CanvasTexture(canvas);
  texture.needsUpdate = true;
  texture.colorSpace = THREE.SRGBColorSpace;
  
  // Apply texture to material
  jerseyMaterial.map = texture;
  jerseyMaterial.needsUpdate = true;
};

// Watch for texture updates
watch(() => props.canvasTexture, (newCanvas) => {
  if (newCanvas) {
    updateTexture(newCanvas);
  }
});

onMounted(() => {
  setupScene();
});

onBeforeUnmount(() => {
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId);
  }
  window.removeEventListener('resize', handleResize);
  renderer?.dispose();
  controls?.dispose();
});
</script>

<template>
  <div ref="containerRef" class="w-full h-full rounded-lg overflow-hidden"></div>
</template>
