/*
RSK World – Tower Defense 3D Evolution (Main v3)
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 { OrbitControls } from 'three/addons/controls/OrbitControls.js';

import { createDefaultPath, createPathLine, createOffsetPath } from './components/Path.js';
import { Enemy } from './components/Enemy.js';
import { EnemyFactory } from './components/EnemyFactory.js';
import { Tower } from './components/Tower.js';
import { MageTower } from './components/MageTower.js';
import { Projectile } from './components/Projectile.js';
import { WaveManager } from './components/WaveManager.js';
import { UIManager } from './components/UIManager.js';
import { Wall } from './components/Wall.js';
import { Environment } from './components/Environment.js';
import { VillagerGLTF } from './components/VillagerGLTF.js';
import { VillageManager } from './components/Village.js';
import { SelectionManager, UpgradeSystem } from './components/UpgradeSystem.js';
import { ResourceState, GoldMine, ElixirCollector, Storage } from './components/Resources.js';
import { Grid } from './components/Grid.js';
import { Barracks } from './components/Barracks.js';
import { AllyUnit } from './components/AllyUnit.js';

const GameConfig = {
	initialGold: 180,
	initialLives: 15,
	costs: { 
		tower: 150, 
		mage: 400, 
		wall: 60, 
		mine: 200, 
		collector: 200, 
		storage: 300, 
		barracks: 450 
	},
	renderPixelRatio: Math.min(window.devicePixelRatio, 2),
	villagerModelUrl: 'https://cdn.jsdelivr.net/gh/KhronosGroup/glTF-Sample-Models@master/2.0/WalkingLady/glTF/WalkingLady.gltf',
	enemyTypes: {
		barbarian: { variant: 'barbarian', speed: 3.4, health: 180, radius: 0.6 },
		archer:    { variant: 'archer',    speed: 4.2, health: 140, radius: 0.55 },
		giant:     { variant: 'giant',     speed: 2.5, health: 600, radius: 0.9 },
		dragon:    { variant: 'dragon',    speed: 4.8, health: 250, radius: 0.8, isFlying: true },
		crobot:    { variant: 'crobot',    speed: 2.0, health: 1200, radius: 1.2 }
	}
};

class Game {
	constructor(container) {
		this.container = container;
		this.clock = new THREE.Clock();
		this.scene = new THREE.Scene();
		this.scene.background = new THREE.Color(0x030712);
		this.camera = new THREE.PerspectiveCamera(50, 1, 0.1, 1000);
		this.camera.position.set(30, 25, 30);
		
		this.renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: 'high-performance' });
		this.renderer.setPixelRatio(GameConfig.renderPixelRatio);
		this.renderer.shadowMap.enabled = true;
		this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
		this.renderer.outputColorSpace = THREE.SRGBColorSpace;
		this.container.appendChild(this.renderer.domElement);

		this.controls = new OrbitControls(this.camera, this.renderer.domElement);
		this.controls.enableDamping = true;
		this.controls.minDistance = 15;
		this.controls.maxDistance = 100;

		this.raycaster = new THREE.Raycaster();
		this.pointer = new THREE.Vector2();

		this.pathPoints = createDefaultPath();
		this.pathLine = createPathLine(this.pathPoints);
		this.scene.add(this.pathLine);

		this.enemies = [];
		this.towers = [];
		this.walls = [];
		this.producers = [];
		this.villagers = [];
		this.projectiles = [];
		this.barracks = [];
		this.allies = [];

		this.state = {
			gold: GameConfig.initialGold,
			elixir: 50,
			builders: 1,
			lives: GameConfig.initialLives,
			wave: 0,
			buildMode: 'none'
		};

		this.resources = new ResourceState();
		this.resources.gold = this.state.gold;
		this.resources.elixir = this.state.elixir;

		this.waveManager = new WaveManager();
		this.enemyFactory = new EnemyFactory(this.pathPoints, GameConfig.enemyTypes);
		this.selection = new SelectionManager(this.scene);
		this.upgrades = new UpgradeSystem();
		
		this.ui = new UIManager(this.state, {
			onSetBuildMode: (m) => this.state.buildMode = m,
			onStartWave: () => this.startWave(),
			onSpawnVillager: () => this.spawnVillager(),
			onToggleDayNight: (m) => this.setDayNight(m),
			onUpgradeSelected: () => this.onUpgradeSelected(),
			getSelectedInfo: () => this.getSelectedInfo()
		});

		this.grid = new Grid(1.5);
		this.setupScene();
		this.addEventListeners();
		this.onResize();
		this.animate();
	}

	setupScene() {
		this.hemisphereLight = new THREE.HemisphereLight(0x1e293b, 0x020617, 0.8);
		this.scene.add(this.hemisphereLight);
		
		this.sunLight = new THREE.DirectionalLight(0xffffff, 1.2);
		this.sunLight.position.set(40, 60, 20);
		this.sunLight.castShadow = true;
		this.sunLight.shadow.mapSize.set(2048, 2048);
		this.scene.add(this.sunLight);

		const groundGeo = new THREE.PlaneGeometry(200, 200);
		const groundMat = new THREE.MeshPhongMaterial({ color: 0x0f172a });
		this.groundPlane = new THREE.Mesh(groundGeo, groundMat);
		this.groundPlane.rotation.x = -Math.PI / 2;
		this.groundPlane.receiveShadow = true;
		this.scene.add(this.groundPlane);

		this.env = new Environment(this.scene, this.pathPoints);
		this.village = new VillageManager(this.scene, new THREE.Vector3(-45, 0, 30));
		this.village.spawnDefault();
		this.scene.fog = new THREE.FogExp2(0x030712, 0.008);
	}

	addEventListeners() {
		window.addEventListener('resize', () => this.onResize());
		this.renderer.domElement.addEventListener('pointerdown', (e) => this.onPointerDown(e));
	}

	onResize() {
		const w = this.container.clientWidth;
		const h = this.container.clientHeight;
		this.camera.aspect = w / h;
		this.camera.updateProjectionMatrix();
		this.renderer.setSize(w, h);
	}

	onPointerDown(event) {
		const rect = this.renderer.domElement.getBoundingClientRect();
		this.pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
		this.pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
		this.raycaster.setFromCamera(this.pointer, this.camera);

		if (this.state.buildMode === 'none') {
			this._handleSelection();
			return;
		}

		const hits = this.raycaster.intersectObject(this.groundPlane);
		if (hits.length === 0) return;
		const point = hits[0].point;

		const step = 1.5;
		const snapped = new THREE.Vector3(
			Math.round(point.x / step) * step,
			0,
			Math.round(point.z / step) * step
		);

		this._tryPlaceByMode(snapped);
	}

	_handleSelection() {
		const candidates = [
			...this.towers.map(t => t.group),
			...this.walls.map(w => w.group),
			...this.producers.map(p => p.group)
		];
		const hits = this.raycaster.intersectObjects(candidates, true);
		if (hits.length > 0) {
			let obj = hits[0].object;
			while (obj.parent && !obj.userData.ref) { obj = obj.parent; }
			const ref = obj.userData.ref;
			if (ref) {
				this.selection.select(obj);
				this._selected = { type: ref.constructor.name.toLowerCase().replace('tower',''), ref };
				this.ui.update(this.state);
			}
		} else {
			this.selection.clear();
			this._selected = null;
			this.ui.update(this.state);
		}
	}

	_tryPlaceByMode(pos) {
		const mode = this.state.buildMode;
		const cost = GameConfig.costs[mode] || 150;

		let factory = null;
		let span = 1;

		switch(mode) {
			case 'tower': factory = () => new Tower(pos); span = 2; break;
			case 'mage': factory = () => new MageTower(pos); span = 2; break;
			case 'wall': factory = () => new Wall(pos); span = 1; break;
			case 'mine': factory = () => new GoldMine(pos); span = 2; break;
			case 'collector': factory = () => new ElixirCollector(pos); span = 2; break;
			case 'storage': factory = () => new Storage(pos); span = 2; break;
			case 'barracks': factory = () => new Barracks(pos); span = 3; break;
		}

		if (!factory) return;
		if (!this.grid.canPlaceAt(pos.x, pos.z, span)) { this.ui.flashHint('Space Occupied!'); return; }
		if (!this.resources.spendGold(cost)) { this.ui.flashHint('Need more Gold!'); return; }

		const instance = factory();
		instance.group.userData.ref = instance; 
		instance.addTo(this.scene);
		this.grid.occupyAt(pos.x, pos.z, span);
		
		if (mode.includes('tower') || mode === 'mage') this.towers.push(instance);
		else if (mode === 'wall') this.walls.push(instance);
		else if (mode === 'barracks') this.barracks.push(instance);
		else this.producers.push(instance);

		this.state.gold = this.resources.gold;
		this.ui.update(this.state);
	}

	getSelectedInfo() {
		if (!this._selected) return null;
		const { type, ref } = this._selected;
		const level = ref.level || 1;
		if (level >= this.upgrades.maxLevel) return { type, level, cost: '-', canAfford: false };
		const nextLevel = level + 1;
		const cost = this.upgrades.getUpgradeCost(type === 'mage' ? 'tower' : type, nextLevel);
		return { type, level, cost, canAfford: this.resources.gold >= cost };
	}

	onUpgradeSelected() {
		const info = this.getSelectedInfo();
		if (!info || info.cost === '-') return;
		if (this.resources.spendGold(info.cost)) {
			this.state.gold = this.resources.gold;
			const ref = this._selected.ref;
			const nextLevel = ref.level + 1;
			
			// APPLY UPGRADE PROPERLY USING UPGRADESYSTEM
			if (this._selected.type === 'wall') {
				this.upgrades.applyWallUpgrade(ref, nextLevel);
			} else {
				this.upgrades.applyTowerUpgrade(ref, nextLevel);
				// Visual Pulse
				ref.group.scale.set(1.5, 1.5, 1.5);
				setTimeout(() => ref.group && ref.group.scale.set(1, 1, 1), 300);
			}
			
			this.ui.update(this.state);
			this.ui.flashHint('Upgraded!');
			console.debug('Tower Upgraded', { type: this._selected.type, nextLevel });
		} else {
			this.ui.flashHint('Need more Gold!');
		}
	}

	spawnVillager() {
		const v = new VillagerGLTF(this.pathPoints, GameConfig.villagerModelUrl);
		v.addTo(this.scene);
		this.villagers.push(v);
	}

	setDayNight(mode) {
		const night = mode === 'night';
		this.scene.background.set(night ? 0x020617 : 0x030712);
		this.hemisphereLight.intensity = night ? 0.4 : 0.8;
		this.sunLight.intensity = night ? 0.3 : 1.2;
		this.scene.fog.density = night ? 0.015 : 0.008;
	}

	startWave() {
		if (this.waveManager.isSpawning) return;
		this.state.wave++;
		this.waveManager.startWave(this.state.wave);
		this.ui.update(this.state);
	}

	spawnEnemy(type) {
		const enemy = this.enemyFactory.spawn(type);
		// Health scaling with wave
		const hpScaling = 1 + this.state.wave * 0.25;
		enemy.maxHealth = Math.round(enemy.maxHealth * hpScaling);
		enemy.health = enemy.maxHealth;
		enemy.obstacles = this.walls;
		enemy.addTo(this.scene);
		this.enemies.push(enemy);
	}

	spawnProjectile(p) { this.projectiles.push(p); p.addTo(this.scene); }

	animate() {
		requestAnimationFrame(() => this.animate());
		const delta = Math.min(this.clock.getDelta(), 0.05);
		this.controls.update();
		
		this.waveManager.update(delta, (t) => this.spawnEnemy(t));

		for (let i = this.enemies.length - 1; i >= 0; i--) {
			const e = this.enemies[i];
			e.update(delta);
			if (e.reachedEnd) {
				this.state.lives--;
				e.removeFrom(this.scene);
				this.enemies.splice(i, 1);
				this.ui.update(this.state);
				if (this.state.lives <= 0) this.ui.flashHint('GAME OVER');
			} else if (!e.alive) {
				const reward = Math.floor(15 * (1 + this.state.wave * 0.15));
				this.resources.earnGold(reward);
				e.removeFrom(this.scene);
				this.enemies.splice(i, 1);
			}
		}

		for (const t of this.towers) t.update(delta, this.enemies, (p) => this.spawnProjectile(p));
		for (let i = this.projectiles.length - 1; i >= 0; i--) {
			const p = this.projectiles[i];
			p.update(delta);
			if (!p.alive) { 
				p.removeFrom(this.scene); 
				this.projectiles.splice(i, 1); 
			}
		}

		for (const pr of this.producers) pr.update(delta, this.resources);
		for (const b of this.barracks) b.update(delta, (type, pos) => this.spawnAlly(type, pos));
		for (const a of this.allies) a.update(delta, this.enemies);

		this.state.gold = this.resources.gold;
		this.state.elixir = this.resources.elixir;
		this.ui.update(this.state); // Ensure UI syncs
		
		this.renderer.render(this.scene, this.camera);
	}

	spawnAlly(type, pos) {
		const a = new AllyUnit(pos);
		a.addTo(this.scene);
		this.allies.push(a);
	}
}

const game = new Game(document.getElementById('game-container'));
