/*
RSK World – Tower Defense 3D (Refined Tower v2)
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 { Projectile } from './Projectile.js';

export class Tower {
	constructor(position) {
		this.position = position.clone();
		this.level = 1;
		this.damageMultiplier = 1.0;
		this.range = 10.0;
		this.fireCooldown = 0.8;
		this._cd = 0;
		this.target = null;
		this.group = this._createMesh();
		this.group.position.copy(this.position);
	}

	_createMesh() {
		const g = new THREE.Group();
		
		const plinth = new THREE.Mesh(
			new THREE.BoxGeometry(2.4, 0.4, 2.4), 
			new THREE.MeshStandardMaterial({ color: 0x334155, roughness: 0.9 })
		);
		plinth.position.y = 0.2; plinth.castShadow = true; plinth.receiveShadow = true; g.add(plinth);
		
		const body = new THREE.Mesh(
			new THREE.CylinderGeometry(0.8, 1.0, 3.0, 6),
			new THREE.MeshStandardMaterial({ color: 0x475569, roughness: 0.85 })
		);
		body.position.y = 0.4 + 1.5; body.castShadow = true; body.receiveShadow = true; g.add(body);
		
		// Level Indicator (Floating Rings)
		this._levelIndicators = new THREE.Group();
		this._levelIndicators.position.y = 5.0;
		g.add(this._levelIndicators);
		this._updateLevelVisuals();

		this._head = new THREE.Group();
		this._head.position.y = 3.6;
		g.add(this._head);

		const headGeo = new THREE.BoxGeometry(1.2, 0.6, 1.2);
		const headMat = new THREE.MeshStandardMaterial({ color: 0x64748b, metalness: 0.2 });
		const head = new THREE.Mesh(headGeo, headMat);
		head.castShadow = true;
		this._head.add(head);

		const barrelMat = new THREE.MeshStandardMaterial({ color: 0x06b6d4, emissive: 0x0891b2, emissiveIntensity: 0.5 });
		const barrel1 = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 1.5, 8), barrelMat);
		barrel1.rotation.x = Math.PI / 2;
		barrel1.position.set(0.3, 0, 0.6);
		this._head.add(barrel1);

		const barrel2 = barrel1.clone();
		barrel2.position.set(-0.3, 0, 0.6);
		this._head.add(barrel2);

		this._muzzle = new THREE.Object3D();
		this._muzzle.position.set(0, 0, 1.2);
		this._head.add(this._muzzle);

		return g;
	}

	_updateLevelVisuals() {
		if (!this._levelIndicators) return;
		while(this._levelIndicators.children.length) this._levelIndicators.remove(this._levelIndicators.children[0]);
		
		for (let i = 0; i < this.level; i++) {
			const ring = new THREE.Mesh(
				new THREE.TorusGeometry(0.3 + i * 0.15, 0.04, 8, 24),
				new THREE.MeshBasicMaterial({ color: 0x22d3ee, transparent: true, opacity: 0.7 })
			);
			ring.rotation.x = Math.PI / 2;
			ring.position.y = i * 0.2;
			this._levelIndicators.add(ring);
		}
	}

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

	_updateTarget(enemies) {
		let best = null; let bestDistSq = Infinity; const myPos = this.group.position;
		for (const e of enemies) {
			if (!e.alive || e.reachedEnd) continue;
			const dSq = myPos.distanceToSquared(e.group.position);
			if (dSq < this.range * this.range && dSq < bestDistSq) { 
				best = e; 
				bestDistSq = dSq; 
			}
		}
		this.target = best;
	}

	_aim(delta) { 
		if (!this.target) return; 
		const to = this.target.group.position.clone().sub(this.group.position); 
		const targetAngle = Math.atan2(to.x, to.z);
		this._head.rotation.y = THREE.MathUtils.lerp(this._head.rotation.y, targetAngle, delta * 10);
	}

	_tryFire(spawnCb) {
		if (!this.target || this._cd > 0) return;
		const origin = new THREE.Vector3(); 
		this._muzzle.getWorldPosition(origin);
		const dmg = Math.round(25 * this.damageMultiplier);
		this.target.takeDamage(dmg);
		const proj = new Projectile(origin, this.target, { damage: 0 });
		spawnCb(proj); 
		this._cd = this.fireCooldown;
	}

	update(delta, enemies, spawnCb) { 
		this._cd = Math.max(0, this._cd - delta); 
		this._updateTarget(enemies); 
		this._aim(delta); 
		this._tryFire(spawnCb); 
		
		if (this._levelIndicators) {
			this._levelIndicators.rotation.y += delta;
			// check if level changed during update (from external)
			if (this._levelIndicators.children.length !== this.level) {
				this._updateLevelVisuals();
			}
		}
	}
}
