import { MissionLog, NotificationPayload, prisma } from "@repo/db";
import { io } from "index";
import cron from "node-cron";

const removeMission = async (id: number, reason: string) => {
	const log: MissionLog = {
		type: "completed-log",
		auto: true,
		timeStamp: new Date().toISOString(),
		data: {},
	};

	const updatedMission = await prisma.mission.update({
		where: {
			id: id,
		},
		data: {
			state: "finished",
			missionLog: {
				push: log as any,
			},
		},
	});
	io.to("dispatchers").emit("new-mission", { updatedMission });
	io.to("dispatchers").emit("notification", {
		type: "mission-auto-close",
		status: "chron",
		message: `Einsatz ${updatedMission.publicId} wurde aufgrund ${reason} geschlossen.`,
		data: {
			missionId: updatedMission.id,
			publicMissionId: updatedMission.publicId,
		},
	} as NotificationPayload);

	console.log(`Mission ${updatedMission.id} closed due to inactivity.`);
};

const removeClosedMissions = async () => {
	const oldMissions = await prisma.mission.findMany({
		where: {
			state: "running",
		},
	});
	oldMissions.forEach(async (mission) => {
		const lastAlert = (mission.missionLog as unknown as MissionLog[]).find((l) => {
			return l.type === "alert-log";
		});

		const lastAlertTime = lastAlert ? new Date(lastAlert.timeStamp) : null;

		const allStationsInMissionChangedFromStatus4to1Or8to1 = mission.missionStationIds.every(
			(stationId) => {
				const status4Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
					return (
						l.type === "station-log" &&
						l.data?.stationId === stationId &&
						l.data?.newFMSstatus === "4"
					);
				});
				const status8Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
					return (
						l.type === "station-log" &&
						l.data?.stationId === stationId &&
						l.data?.newFMSstatus === "8"
					);
				});

				const status1Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
					return (
						l.type === "station-log" &&
						l.data?.stationId === stationId &&
						l.data?.newFMSstatus === "1"
					);
				});
				const status6Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
					return (
						l.type === "station-log" &&
						l.data?.stationId === stationId &&
						l.data?.newFMSstatus === "6"
					);
				});
				return (
					(status4Log !== -1 || status8Log !== -1) &&
					(status1Log !== -1 || status6Log !== -1) &&
					(status4Log < status1Log ||
						status8Log < status1Log ||
						status8Log < status6Log ||
						status1Log < status6Log)
				);
			},
		);

		const missionHasManualReactivation = (mission.missionLog as unknown as MissionLog[]).some(
			(l) => l.type === "reopened-log",
		);

		if (missionHasManualReactivation) return;

		if (!lastAlertTime) return;

		const lastStatus1or6Log = (mission.missionLog as unknown as MissionLog[])
			.filter((l) => {
				return (
					l.type === "station-log" && (l.data?.newFMSstatus === "1" || l.data?.newFMSstatus === "6")
				);
			})
			.sort((a, b) => new Date(b.timeStamp).getTime() - new Date(a.timeStamp).getTime())[0];

		// Case 1: Forgotten Mission, last alert more than 3 Hours ago
		const now = new Date();
		if (now.getTime() - lastAlertTime.getTime() > 1000 * 60 * 180)
			return removeMission(mission.id, "inaktivität");

		// Case 2: All stations in mission changed from status 4 to 1/6 or from status 8 to 1/6, Status 1/6 change less more 5 minutes ago
		if (
			allStationsInMissionChangedFromStatus4to1Or8to1 &&
			lastStatus1or6Log &&
			now.getTime() - new Date(lastStatus1or6Log.timeStamp).getTime() > 1000 * 60 * 5
		)
			return removeMission(mission.id, "dem freimelden aller Stationen");
	});
};
const removeConnectedAircrafts = async () => {
	const connectedAircrafts = await prisma.connectedAircraft.findMany({
		where: {
			logoutTime: null,
		},
	});

	connectedAircrafts.forEach(async (aircraft) => {
		const lastUpdate = new Date(aircraft.lastHeartbeat);
		const now = new Date();
		if (now.getTime() - lastUpdate.getTime() > 12 * 60 * 60 * 1000) {
			await prisma.connectedAircraft.update({
				where: { id: aircraft.id },
				data: { logoutTime: now },
			});

			console.log(`Aircraft ${aircraft.id} disconnected due to inactivity.`);
		}
	});
};

cron.schedule("*/1 * * * *", async () => {
	try {
		await removeClosedMissions();
		await removeConnectedAircrafts();
	} catch (error) {
		console.error("Error on cron job:", error);
	}
});
