import * as mc from '@minecraft/server';


import * as malfunctionClass from "./events/malfunction_event";
import * as appleClass from "./events/apple_event";
import * as sneakDanceClass from "./events/sneak_dance_event";
import * as darknessClass from "./events/darkness_event";
import * as teapartyClass from "./events/teaparty_event";
import * as itemClass from "./events/item_event";

import * as main from './main';

// Current active event
export let tickingEvent = null;
export let lastTickingEvent = null;
let lastEventId = -1;
export const randInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }
// Activate the event with the AI friend.

function TaskCount(friend_exe) {
	return friend_exe.getProperty("blocklab_friend_exe:task_counter");
}

export function startEvent(event, friend_exe, forceStart, manuallyStart = false) {
	if (main.Stage(friend_exe) > 0) return;

	if (tickingEvent && !forceStart) return;

	const instance = new (event.class)();
	if (manuallyStart) {
		instance.manuallyStart = true;
	}

	friend_exe.setProperty("blocklab_friend_exe:currentevent", instance.eventID);
	const taskCount = TaskCount(friend_exe);
	friend_exe.setProperty("blocklab_friend_exe:task_counter", taskCount + 1);

	instance.activate(friend_exe);
	tickingEvent = instance;
	objectiveInSound(event, friend_exe);
	mc.world.getPlayers().forEach((player) => {
		player.runCommand(`scriptevent blocklab_friend_exe:playerdata t.objective = 1`);
	});
};

function objectiveInSound(event, friend_exe) {
	const moodStage = main.MoodStage(main.Mood(friend_exe));
	let sound;
	if (moodStage == 5) {
		sound = "happy";
	} else if (moodStage == 4) {
		sound = "friendly";
	} else if (moodStage == 3) {
		sound = "okay";
	} else if (moodStage == 2) {
		sound = "unhappy";
	}
	if (sound) friend_exe.runCommand(`execute as @a at @s run playsound mob.ai-friend.objectivesound_in_${sound}`);
}

export function stopEvent(friend_exe) {
	if (tickingEvent != null) {
		tickingEvent.deactivate(friend_exe);
		mc.world.getPlayers().forEach((player) => {
			player.runCommand(`scriptevent blocklab_friend_exe:playerdata t.objective = 0`);
		});
	}
	tickingEvent = null;
}

export function isEventActive(eventID) { return tickingEvent && tickingEvent.eventID === eventID; }

export function resetTimer(context = "normal") {
	nextEventTime = getRandomNextEventTime(context);
}

export let nextEventTime = 20;
export function setNextEventTime(time) { nextEventTime = time; }


export function isGoodTime() {
	const time = mc.world.getTimeOfDay();
	return !(time >= 12500 && time < 24000);
}


// Important functions
// Event Pool!

const EVENT_IDS = {
	ITEM: 5,
	DANCE: 3,
	TEAPARTY: 4,
	APPLE: 2,
	DARKNESS: 6,
	NONE: -1 // kein Event
};

const EVENT_POOLS = {
	0: {
		day: [
			{ id: EVENT_IDS.ITEM, chance: 0.7 },
			{ id: EVENT_IDS.DANCE, chance: 0.3 }
		],
		night: [
			{ id: EVENT_IDS.DARKNESS, chance: 0.4 },
			{ id: EVENT_IDS.NONE, chance: 0.6 }
		]
	},
	1: {
		day: [
			{ id: EVENT_IDS.ITEM, chance: 0.4 },
			{ id: EVENT_IDS.DANCE, chance: 0.4 },
			{ id: EVENT_IDS.TEAPARTY, chance: 0.2 }
		],
		night: [
			{ id: EVENT_IDS.DARKNESS, chance: 0.3 },
			{ id: EVENT_IDS.ITEM, chance: 0.6 },
			{ id: EVENT_IDS.NONE, chance: 0.2 }
		]
	},
	2: {//DEFAULT POOL
		day: [
			{ id: EVENT_IDS.ITEM, chance: 0.4 },
			{ id: EVENT_IDS.DANCE, chance: 0.2 },
			{ id: EVENT_IDS.TEAPARTY, chance: 0.2 },
			{ id: EVENT_IDS.APPLE, chance: 0.2 }
		],
		night: [
			{ id: EVENT_IDS.DARKNESS, chance: 0.3 },
			{ id: EVENT_IDS.NONE, chance: 0.3 },
			{ id: EVENT_IDS.ITEM, chance: 0.4 }
		]
	}
	// Du kannst Tag 2, 3, 4 usw. beliebig ergänzen
};

export function FindNextEvent() {
	const day = mc.world.getDay();
	const dayTime = isGoodTime();

	const poolData = EVENT_POOLS[day] ?? EVENT_POOLS[2]; // fallback zu Tag 2
	const pool = dayTime ? poolData.day : poolData.night;

	const eventId = pickEventFromPool(pool, lastEventId);

	if (eventId === EVENT_IDS.NONE) return null;

	//const taskCount = TaskCount(main.friend_exe);
	//let nextEvent = getRandomEventFromType(EVENT_TYPE.CUTE);
	//if (day == 0) {
	//	nextEvent = EVENT_LIST[3];
	//}
	const event = EVENT_LIST.find(e => e.eventID === eventId);
	return event ?? null;
}

function pickEventFromPool(pool, lastId) {
	const blockedRepeatIds = [2, 3, 4, 6, -1];
	//const filteredPool = pool;

	//mc.world.sendMessage(`Debug: neues event wird gesucht darf aber nicht ${lastId} sein`);

	const filteredPool = pool.filter(e => {
		const isBlocked = blockedRepeatIds.includes(e.id);
		const isRepeat = e.id === lastId;
		if (isBlocked && isRepeat) {
			//mc.world.sendMessage(`Debug: Event ${e.id} rausgefiltert`);
			return false;
		}
		return true;
	});
	if (filteredPool.length === 0) return EVENT_IDS.NONE;

	const total = filteredPool.reduce((sum, e) => sum + e.chance, 0);
	const rnd = Math.random() * total;

	let cumulative = 0;
	for (const e of filteredPool) {
		cumulative += e.chance;
		if (rnd < cumulative) return e.id;
	}
	return EVENT_IDS.NONE;
}

// Random Event Frequency

function getRandomNextEventTime(context = "normal") {
	//600 sind 10 minuten sprich ein halber tag!

	const day = mc.world.getDay();
	let timer = 120;//5 task am tag in 10 minuten!

	if (context == "spawn") {
		timer = 20;
	} else if (context == "load") {
		timer = 20;
	} else if (context == "stage0") {
		timer = 40;
	} else if (context == "complete") {
		timer = 70;
	} else if (context == "failed") {
		timer = 40;
	} else if (context == "day") {
		timer = 20;//new day
	} else if (context == "night") {
		timer = 200;
	}
	if (!isGoodTime()) {//in der nacht sollen keine events kommen kaum
		if (context == "load") {
			timer = 40;
		} else {
			timer = 300;
		}
	}
	if (context == "none") {
		timer = 60;
	}
	if (context == "test") {
		timer = 4
	}
	//timer = 10;
	//mc.world.sendMessage(`Debug: Reset Timer! day ${day} time: ${timer} context: ${context}`);
	return timer;
}

export function update(friend_exe, stage, day, mood, moodStage) {
	nextEventTime--;

	if (nextEventTime <= 0) {
		if (tickingEvent) {
			nextEventTime = 8;
		} else if (moodStage == 0) {
			nextEventTime = 40;
		} else if (main.friend_exeHasTarget || stage > 0) {
			nextEventTime = 8;
		} else {
			resetTimer();
			if (stage == 0) {
				let nextEvent = FindNextEvent();
				if (nextEvent) {
					startEvent(nextEvent, friend_exe, false);
				} else {
					lastEventId = -1;
					resetTimer("none");
				}
			}
		}
	}

	//Update current Event
	if (tickingEvent) {
		//friend_exe.triggerEvent("blocklab_friend_exe:switch_to_standard_attack"); > in start event ? wo ist der sinn?`Darkness event bug wenn endet wegen distance
		tickingEvent.tick(friend_exe, mood, moodStage);
		if (!tickingEvent.isActive) {
			const complete = tickingEvent.complete ? "complete" : "failed";
			lastEventId = tickingEvent.eventID;
			//mc.world.sendMessage(`Debug Last Event ID = ${lastEventId}`);
			lastTickingEvent = tickingEvent;
			tickingEvent = null;
			resetTimer(complete);
			mc.world.getPlayers().forEach((player) => {
				player.runCommand(`scriptevent blocklab_friend_exe:playerdata t.objective = 0`);
			});
		}
	}
}


export const EVENT_TYPE = {
	CUTE: "Cutee",
	EVIL: "Evil",
	SCARY: "Scary",
	MALFUNCTION: "Malfunction"
};

export const EVENT_LIST = [
	{
		eventID: 2,
		class: appleClass.default,
		type: EVENT_TYPE.CUTE,
		chance: 0.2
	},
	{
		eventID: 3,
		class: sneakDanceClass.default,
		type: EVENT_TYPE.CUTE,
		chance: 0.2
	},
	{
		eventID: 4,
		class: teapartyClass.default,
		type: EVENT_TYPE.CUTE,
		chance: 0.1
	},
	{
		eventID: 5,
		class: itemClass.default,
		type: EVENT_TYPE.CUTE,
		chance: 0.3
	},
	{
		eventID: 1,
		class: malfunctionClass.default,
		type: EVENT_TYPE.MALFUNCTION
	},
	{
		eventID: 6,
		class: darknessClass.default,
		type: EVENT_TYPE.CUTE,
		chance: 1
	}
]

export function EventInstance(event) {
	return new (event.class)();
}

// Get a random event 
export function getRandomEvent() {
	const randomIndex = Math.floor(Math.random() * EVENT_LIST.length);
	return EVENT_LIST[randomIndex];
}

// Get a random event filtered by its type, weighted by chance
export function getRandomEventFromType(eventType) {
	const filteredEvents = EVENT_LIST.filter(
		event => event.type === eventType && canStartEvent(event.eventID)
	);
	if (filteredEvents.length === 0) return null;

	// Calculate total weight (sum of all chances)
	const totalChance = filteredEvents.reduce((sum, event) => sum + event.chance, 0);

	// Generate a random number between 0 and totalChance
	const random = Math.random() * totalChance;

	let cumulative = 0;
	for (const event of filteredEvents) {
		cumulative += event.chance;
		if (random < cumulative) {
			return event;
		}
	}
	return null;
}

function canStartEvent(eventID) {
	const day = mc.world.getDay();
	if (eventID == 6) {
		if (day < 4) {
			return false;
		} else {
			return main.isNighttime();
		}
		//wenn darkness dann schauen dass er nicht wütend sein kann in den ersten 7 tagen & wenn die mood nicht happy ist
	}
	if (lastTickingEvent) {
		//	return lastTickingEvent.eventID != eventID;
	}
	return true;
}

export function getEvemtFromID(eventID) {
	const malfunctionEvent = EVENT_LIST.find(event => event.eventID == eventID);
	return malfunctionEvent || null;
}

// Get the malfunction event from the EVENT_LIST.
export function getMalfunction() {
	const malfunctionEvent = EVENT_LIST.find(event => event.eventID == 1);
	return malfunctionEvent || null;
}

export function getCake() {
	return EVENT_LIST[2]
}