/*
RSK World – Tower Defense 3D (Villager)
For support, licensing, or custom development inquiries: help@rskworld.in • Phone/WhatsApp: +91 9330539277
Website: RSK World • Business Inquiries: help@rskworld.in
🤝 Contributing: Suggestions and improvements are welcome!
*/

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

export class VillagerGLTF {
	constructor(pathPoints, url, bounds = 55) {
		this.path = pathPoints;
		this.url = url;
		this.bounds = bounds;
		this.group = new THREE.Group();
		this.group.position.copy(this._randomPointFarFromPath());
		this.speed = THREE.MathUtils.randFloat(1.2, 1.8);
		this.radius = 0.5;
		this.mixer = null;
		this.action = null;
		this.alive = true;
		this._target = this._randomPointFarFromPath();
		this._loadModel();
	}

	_distanceToPath(point) {
		let min = Infinity;
		for (let i = 0; i < this.path.length - 1; i++) {
			const a = this.path[i];
			const b = this.path[i + 1];
			const ab = new THREE.Vector3().subVectors(b, a);
			const ap = new THREE.Vector3().subVectors(point, a);
			const t = THREE.MathUtils.clamp(ap.dot(ab) / ab.lengthSq(), 0, 1);
			const proj = new THREE.Vector3().copy(a).add(ab.multiplyScalar(t));
			const d = proj.distanceTo(point);
			if (d < min) min = d;
		}
		return min;
	}

	_randomPointFarFromPath() {
		for (let k = 0; k < 100; k++) {
			const x = THREE.MathUtils.randFloatSpread(this.bounds * 2);
			const z = THREE.MathUtils.randFloatSpread(this.bounds * 2);
			const p = new THREE.Vector3(x, 0, z);
			if (this._distanceToPath(p) > 6.0) return p;
		}
		return new THREE.Vector3(THREE.MathUtils.randFloat(-this.bounds, this.bounds), 0, THREE.MathUtils.randFloat(-this.bounds, this.bounds));
	}

	_loadModel() {
		const loader = new GLTFLoader();
		loader.load(this.url, (gltf) => {
			const root = gltf.scene;
			root.traverse((o) => { if (o.isMesh) { o.castShadow = true; o.receiveShadow = true; } });
			root.scale.set(1.0, 1.0, 1.0);
			this.group.add(root);
			if (gltf.animations && gltf.animations.length) {
				this.mixer = new THREE.AnimationMixer(root);
				let walk = gltf.animations.find(a => /walk/i.test(a.name)) || gltf.animations[0];
				this.action = this.mixer.clipAction(walk);
				this.action.play();
			}
		}, undefined, () => {
			const geo = new THREE.ConeGeometry(0.6, 1.8, 12);
			const mat = new THREE.MeshStandardMaterial({ color: 0x10b981 });
			const m = new THREE.Mesh(geo, mat);
			m.castShadow = true; m.receiveShadow = true;
			this.group.add(m);
		});
	}

	addTo(scene) { scene.add(this.group); }
	removeFrom(scene) { scene.remove(this.group); }

	update(delta) {
		if (this.mixer) this.mixer.update(delta);
		const pos = this.group.position;
		const dir = this._target.clone().sub(pos);
		const dist = dir.length();
		if (dist < 0.5) {
			this._target = this._randomPointFarFromPath();
			return;
		}
		dir.normalize();
		pos.addScaledVector(dir, this.speed * delta);
		this.group.rotation.y = Math.atan2(dir.x, dir.z);
	}
}
