import { EntityDamageCause, system, world, GameMode } from "@minecraft/server";
import { applyPlayerImpulse } from "../utilities/playerImpulse";
import { banned_wither_structure_detector } from "./structure";
import { banned_wither_marker } from "./marker";

export function banned_wither() {
	banned_wither_structure_detector();
	banned_wither_marker();

	world.afterEvents.entityHitEntity.subscribe((event) => {
		const player = event.hitEntity;
		const damager = event.damagingEntity;

		if (player?.typeId !== "minecraft:player" || !player) return;
	
		// BANNED WITHER DAMAGE
		if (damager?.typeId === "hb_hr:banned_wither") {

			// Increase horizontal knockback for first phase melee
			if (damager.getProperty("hb_hr:phase") === 1) {
				Phase1MeleeKnockback(player, damager);
			}
		}
	});

	world.afterEvents.entityHurt.subscribe((event) => {
		const player = event.hurtEntity;
		if (player?.typeId !== "minecraft:player" || !player) return;

		const damagingEntity = event.damageSource?.damagingEntity;

		// Banned Skull explosion
		if (damagingEntity?.typeId === "hb_hr:banned_skull") {
			BannedSkullAttack(player);
		}
		// Void Sphere damage and knockback
		if (damagingEntity?.typeId === "hb_hr:void_sphere") {
			VoidSphereKnockback(player);
		}
		// Void Sphere Reflectable damage and knockback
		if (damagingEntity?.typeId === "hb_hr:void_sphere_reflectable") {
			VoidSphereKnockback(player);
		}

		// banned_void_skull damage and knockback
		if (damagingEntity?.typeId === "hb_hr:hb_hr:banned_void_skull") {
			VoidSphereKnockback(player);
		}

	});

	world.afterEvents.entityHurt.subscribe((event) => {
		const entity = event.hurtEntity;
		if (entity?.typeId !== "hb_hr:banned_void_skull" || !entity) return;
		const damagingEntity = event.damageSource?.damagingEntity;
		
		// Applay knockback to "hb_hr:banned_void_skull" on player hit
		if (damagingEntity?.typeId === "minecraft:player") {
			VoidSkullKnockback(entity, damagingEntity);
		}
	});

	system.afterEvents.scriptEventReceive.subscribe((event) => {
		if (event.sourceEntity?.typeId !== 'hb_hr:banned_wither' && event.sourceEntity?.typeId !== 'hb_hr:void_sphere_reflectable') return;
		let entity = event.sourceEntity;

		//Dash attack
		if (event.id === 'hb_hr:banned_wither.dash') {
			// Enttiy movement
			const viewDirection = entity.getViewDirection();
			entity.applyKnockback(viewDirection.x, viewDirection.z, 20, 0.1);
			// Player damage
			playerDamageOnDash(entity);
		}
		//Move down
		if (event.id === 'hb_hr:void_sphere_reflectable.move_down') {
			// Enttiy movement
			const viewDirection = entity.getViewDirection();
			// entity.applyKnockback(viewDirection.x, viewDirection.z, 0.7, -0.15);
			entity.applyKnockback(viewDirection.x, viewDirection.z, 0.3, -0.15);
		}

		//Phase 3 - melee attacks
		if (event.id === 'hb_hr:banned_wither.melee') {
			const nearbyPlayers = getPlayersNearEntity(entity, 8);
			if (nearbyPlayers.length > 0) {
				nearbyPlayers.forEach(player => {
					if (event?.message === "first") {
						Phase3MeleeAttack(player, entity, 1, 8)
					}
					if (event?.message === "second") {
						Phase3MeleeAttack(player, entity, 1, 8)
					}
					if (event?.message === "third") {
						Phase3MeleeAttack(player, entity, 1.75, 12)
					}
				});
			}
			// Enttiy movement
			const viewDirection = entity.getViewDirection();
			entity.applyKnockback(viewDirection.x, viewDirection.z, 20, 0.1);
			// Player damage
			playerDamageOnDash(entity);
		}
	});	
}

function BannedSkullAttack(player) {
	let damage = randomInt(3, 4);
	player?.applyDamage(damage, {"cause": EntityDamageCause.entityExplosion});
	player?.addEffect("minecraft:wither", 6*20);
}

function VoidSphereKnockback(player) {
	// Apply damage
	let damage = randomInt(4, 6);
	player.applyDamage(damage, {"cause": EntityDamageCause.entityExplosion});
	
	const playedData1 = player.location;
	// Apply knockback
	system.runTimeout(()=> {
		if (!player.isValid()) return;

		const horizontal_strength = 1.8;
		const playedData2 = player.location;		

		// Direction vector
		const dx = playedData1.x - playedData2.x;
		const dz = playedData1.z - playedData2.z;

		// Normalization
		const distance = Math.sqrt(dx * dx + dz * dz);
		const dirX = dx / distance;
		const dirZ = dz / distance;
		
		const vector = {
			x: dirX*horizontal_strength,
			y: 0.6,
			z: dirZ*horizontal_strength
		}
		applyPlayerImpulse(player, vector);
	}, 2)
}

function Phase1MeleeKnockback(player, damagingEntity) {
	if (!player.isValid()) return;
	const horizontal_strength = 2;
	const knockDirection = getKnockDirection(damagingEntity, player);
	
	const vector = {
		x: knockDirection[0]*horizontal_strength,
		y: 0.4,
		z: knockDirection[1]*horizontal_strength
	}	
	applyPlayerImpulse(player, vector);
}

function Phase3MeleeAttack(player, damagingEntity, strength_multiplier, damageDealt) {
	player.applyDamage(damageDealt, {"cause": EntityDamageCause.entityAttack, "damagingEntity": damagingEntity});
	if (!player.isValid()) return;
	const horizontal_strength = 2;		
	const knockDirection = getKnockDirection(damagingEntity, player);
	
	const vector = {
		x: knockDirection[0]*horizontal_strength*strength_multiplier,
		y: 0.4*strength_multiplier,
		z: knockDirection[1]*horizontal_strength*strength_multiplier
	}

	applyPlayerImpulse(player, vector);
}

function playerDamageOnDash(entity) {
	let chargeDamage = system.runInterval(() => {
		const nearbyPlayers = getPlayersNearEntity(entity, 5);
		if (nearbyPlayers.length > 0) {
			nearbyPlayers.forEach(player => {
				const knockDirection = getKnockDirection(entity, player);

				player.runCommand(`/damage @s 12 entity_attack entity @e[type=hb_hr:banned_wither,c=1]`);
				player.applyKnockback(knockDirection[0], knockDirection[1], -1.1, 0.4);
			});
		}
		// Stop Interval
		let clearChargeDamage = system.runTimeout(() => {
			system.clearRun(clearChargeDamage);
			system.clearRun(chargeDamage);
		}, 20);
	}, 2);
}

export function getPlayersNearEntity(entity, maxDistance) {	
    let players = world.getPlayers({excludeGameModes: [GameMode.creative, GameMode.spectator]});
    const entityPos = entity.location;

    return players.filter(player => {
        const playerPos = player.location;
        const dx = playerPos.x - entityPos.x;
        const dy = playerPos.y - entityPos.y;
        const dz = playerPos.z - entityPos.z;
        
        // Get distance
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
        return distance <= maxDistance;
    });
}

function getKnockDirection(entity, player) {
	const playerPos = player.location;
	const entityPos = entity.location;

	// Direction vector
	const dx = entityPos.x - playerPos.x;
	const dz = entityPos.z - playerPos.z;

	// Normalization
	const distance = Math.sqrt(dx * dx + dz * dz);
	const dirX = dx / distance;
	const dirZ = dz / distance;

	return [dirX, dirZ]
}

function VoidSkullKnockback(entity, player) {
	if (!entity.isValid()) return;
	const knockDirection = getKnockDirection(player, entity);	
	entity.applyKnockback(knockDirection[0], knockDirection[1], -1.5, 0.4);
}

function randomInt(min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

function clamp(value, min, max) {
	return Math.max(min, Math.min(value, max));
}