import { world, system } from "@minecraft/server"
const ENTITY = "sf_nba:peafowl"
const DANCING_TAG = "sf_nba.is_dancing"
const TAME_CHANCE = 3
const BUFFS = [
	{ name: "strength", duration: 1200, amplifier: 2 }
]
function randomInt(min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min
}
function getNearbyPeafowls(player) {
	const peafowls = player.dimension.getEntities({
		type: ENTITY,
		location: player.location,
		maxDistance: 6
	})
	return peafowls
}
function tamePeafowl(player) {
	const peafowls = getNearbyPeafowls(player)
	const dancingPeafowls = JSON.parse(player.getDynamicProperty("sf_nba:dancing_peafowls")).entries
	for (const p in peafowls) {
		if (!peafowls[p].isValid()) continue
		const tameable = peafowls[p].getComponent("minecraft:tameable")
		if (!peafowls[p].getProperty("sf_nba:is_dancing") || !dancingPeafowls.includes(peafowls[p].typeId) || !tameable) continue
		if (TAME_CHANCE < randomInt(1, 100)) continue
		tameable.tame(player)
		peafowls[p].setDynamicProperty("sf_nba:tame_id", player.id)
		dancingPeafowls.splice(p, 1)
		player.setDynamicProperty("sf_nba:dancing_peafowls", JSON.stringify({ entries: dancingPeafowls }))
	}
}
function stopDanceRitual(player) {
	const peafowls = getNearbyPeafowls(player)
	const dancingPeafowls = JSON.parse(player.getDynamicProperty("sf_nba:dancing_peafowls")).entries
	player.removeTag(DANCING_TAG)
	player.setDynamicProperty("sf_nba:dancing_peafowls", JSON.stringify({ entries: [] }))
	for (const p in peafowls) {
		if (!peafowls[p].isValid() || !dancingPeafowls.includes(peafowls[p].typeId)) continue
		peafowls[p].triggerEvent("sf_nba:stop_dancing")
	}
}
class StateMachines {
	static #run(actor, controller) {
		const controllerId = `sf_nba_${controller.name}`
		const states = controller.states
		if (!actor[controllerId]) {
			actor[controllerId] = {
				currentState: Object.keys(states)[0],
				isRunning: false
			}
		}
		const actorState = actor[controllerId]
		const currentState = states[actorState.currentState]
		if (!actorState.isRunning) {
			if (typeof currentState.onEntry == "function") currentState.onEntry()
			actorState.isRunning = true
			return
		}
		if (!currentState.transitions || !currentState.transitions.length) return
		for (const transition of currentState.transitions) {
			if (Object.values(transition).includes(true)) {
				const nextState = Object.keys(transition)
				if (typeof currentState.onExit == "function") currentState.onExit()
				if (typeof states[nextState].onEntry == "function") states[nextState].onEntry()
				actorState.currentState = nextState
				return
			}
		}
	}
	static add(controller) {
		system.runInterval(() => {
			for (const player of world.getPlayers()) {
				this.#run(player, controller(player))
			}
		}, 1)
	}
}
StateMachines.add(actor => {
	const data = {
		name: "peacock",
		states: {
			"default": {
				onEntry: () => {
					actor.sneakTick = 0
					actor.standTick = 0
					actor.stopTick = 0
				},
				transitions: [
					{ "sneak": actor.hasTag(DANCING_TAG) }
				]
			},
			"sneak": {
				onEntry: () => {
					actor.standTick = 0
					actor.sneakTick++
				},
				transitions: [
					{ "stand": !actor.isSneaking && actor.sneakTick < 40 },
					{ "sneak": actor.isSneaking && actor.sneakTick < 40 },
					{ "stop": actor.sneakTick >= 40 || !actor.hasTag(DANCING_TAG) }
				]
			},
			"stand": {
				onEntry: () => {
					actor.sneakTick = 0
					if (actor.standTick <= 10) tamePeafowl(actor)
					actor.standTick++
				},
				transitions: [
					{ "sneak": actor.isSneaking && actor.standTick < 40 },
					{ "stand": !actor.isSneaking && actor.standTick < 40 },
					{ "stop": actor.standTick >= 40 || !actor.hasTag(DANCING_TAG) }
				]
			},
			"stop": {
				onEntry: () => {
					if (!actor.stopTick) stopDanceRitual(actor)
				},
				transitions: [
					{ "default": true }
				]
			}
		}
	}
	return data
})
StateMachines.add(actor => {
	return {
		name: "peacloak",
		states: {
			"default": {
				onEntry: () => {
					actor.runCommand("effect @s slow_falling 0")
				},
				transitions: [
					{ "equipped": actor.getComponent("equippable")?.getEquipment("Chest")?.typeId == "sf_nba:peacloak" && actor.isSneaking && !actor.isOnGround }
				]
			},
			"equipped": {
				onEntry: () => {
					actor.runCommand("effect @s slow_falling infinite 9 true")
				},
				transitions: [
					{ "default": actor.getComponent("equippable")?.getEquipment("Chest")?.typeId != "sf_nba:peacloak" || !actor.isSneaking || actor.isOnGround }
				]
			}
		}
	}
})
system.afterEvents.scriptEventReceive.subscribe(e => {
	if (e.id == "sf_nba:peafowl_dance.entity") {
		e.sourceEntity.danceStartTick = system.currentTick
	}
	if (e.id == "sf_nba:peafowl_dance.player") {
		const { sourceEntity: player } = e
		const dancingPeafowlsDP = player.getDynamicProperty("sf_nba:dancing_peafowls") ?? JSON.stringify({ entries: [] })
		const dancingPeafowls = JSON.parse(dancingPeafowlsDP).entries
		player.danceStartTick = system.currentTick
		player.addTag(DANCING_TAG)
		for (const peafowl of getNearbyPeafowls(player)) {
			if (!peafowl.isValid() || player.danceStartTick > peafowl.danceStartTick) continue
			dancingPeafowls.push(peafowl.typeId)
		}
		player.setDynamicProperty("sf_nba:dancing_peafowls", JSON.stringify({ entries: dancingPeafowls }))
	}
	if (e.id == "sf_nba:peafowl_unfurl") {
		for (const player of world.getPlayers()) {
			const tameId = e.sourceEntity.getDynamicProperty("sf_nba:tame_id")
			if (tameId != player.id) continue
			for (const buff of BUFFS) {
				player.addEffect(buff.name, buff.duration, { amplifier: buff.amplifier, showParticles: false })
			}
		}
	}
})