import {
	HpgValidationState,
	MissionSdsLog,
	MissionStationLog,
	NotificationPayload,
	Prisma,
	prisma,
	User,
} from "@repo/db";
import { Router } from "express";
import { io } from "../index";
import { sendNtfyMission } from "modules/ntfy";
import { sendAlert } from "modules/mission";

const router: Router = Router();

// Get all missions
router.post("/", async (req, res) => {
	try {
		const filter = req.body?.filter || {};
		const missions = await prisma.mission.findMany({
			where: filter,
		});
		res.json(missions);
	} catch (error) {
		console.error(error);
		res.status(500).json({ error: "Failed to fetch missions" });
	}
});

// Get a single mission by ID
router.get("/:id", async (req, res) => {
	const { id } = req.params;
	try {
		const mission = await prisma.mission.findUnique({
			where: { id: Number(id) },
		});
		if (mission) {
			res.json(mission);
		} else {
			res.status(404).json({ error: "Mission not found" });
		}
	} catch (error) {
		console.error(error);
		res.status(500).json({ error: "Failed to fetch mission" });
	}
});

// Create a new mission
router.put("/", async (req, res) => {
	try {
		const startOfToday = new Date();
		startOfToday.setHours(0, 0, 0, 0);

		const missionsTodayCount = await prisma.mission.count({
			where: {
				createdAt: {
					gte: startOfToday,
				},
			},
		});

		const date = new Date();
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are zero-based
		const day = String(date.getDate()).padStart(2, "0");

		const publicId = `__${year}${month}${day}${missionsTodayCount ? missionsTodayCount + 1 : 1}`;
		const newMission = await prisma.mission.create({
			data: {
				...req.body,
				publicId,
			},
		});
		io.to("dispatchers").emit("new-mission", { newMission });
		res.status(201).json(newMission);
	} catch (error) {
		res.status(500).json({ error: "Failed to create mission" });
	}
});

// Update a mission by ID
router.patch("/:id", async (req, res) => {
	const { id } = req.params;
	try {
		const updatedMission = await prisma.mission.update({
			where: { id: Number(id) },
			data: req.body,
		});
		io.to("dispatchers").emit("update-mission", updatedMission);
		res.json(updatedMission);
	} catch (error) {
		console.error(error);
		res.status(500).json({ error: "Failed to update mission" });
	}
});

// Delete a mission by ID
router.delete("/:id", async (req, res) => {
	const { id } = req.params;
	try {
		await prisma.mission.delete({
			where: { id: Number(id) },
		});
		io.to("dispatchers").emit("delete-mission", id);
		res.status(204).send();
	} catch (error) {
		console.error(error);
		res.status(500).json({ error: "Failed to delete mission" });
	}
});

// Send mission

router.post("/:id/send-alert", async (req, res) => {
	const { id } = req.params;
	const { stationId, vehicleName } = req.body as {
		stationId?: number;
		vehicleName?: "ambulance" | "police" | "firebrigade";
	};

	try {
		if (vehicleName) {
			const hpgAircrafts = await prisma.connectedAircraft.findMany({
				where: {
					stationId: Number(id),
					logoutTime: null,
					posH145active: true,
				},
			});

			const newMission = await prisma.mission.update({
				where: {
					id: Number(id),
				},
				data: {
					hpgAmbulanceState: vehicleName === "ambulance" ? "DISPATCHED" : undefined,
					hpgFireEngineState: vehicleName === "firebrigade" ? "DISPATCHED" : undefined,
					hpgPoliceState: vehicleName === "police" ? "DISPATCHED" : undefined,
				},
			});
			hpgAircrafts.forEach((aircraft) => {
				io.to(`desktop:${aircraft.userId}`).emit("hpg-vehicle-update", {
					missionId: id,
					vehicleData: {
						ambulanceState: newMission.hpgAmbulanceState,
						fireEngineState: newMission.hpgFireEngineState,
						policeState: newMission.hpgPoliceState,
					},
				});
			});

			res.status(200).json({
				message: `Rettungsmittel disponiert (${hpgAircrafts.length} Nutzer)`,
			});
			io.to("dispatchers").emit("update-mission", newMission);
			return;
		}
		const { connectedAircrafts, mission } = await sendAlert(Number(id), {
			stationId,
		});

		res.status(200).json({
			message: `Einsatz gesendet (${connectedAircrafts.length} Nutzer) `,
		});
		io.to("dispatchers").emit("update-mission", mission);
	} catch (error) {
		console.error(error);
		res.status(500).json({ error: "Failed to send mission" });
	}
});

router.post("/:id/send-sds", async (req, res) => {
	const sdsMessage = req.body as MissionSdsLog;
	const newMission = await prisma.mission.update({
		where: {
			id: Number(req.params.id),
		},
		data: {
			missionLog: {
				push: sdsMessage as any,
			},
		},
	});

	io.to(`station:${sdsMessage.data.stationId}`).emit("sds-message", sdsMessage);
	res.json({
		message: "SDS message sent",
		mission: newMission,
	});
	io.to("dispatchers").emit("update-mission", newMission);
});

router.post("/:id/validate-hpg", async (req, res) => {
	try {
		const { id } = req.params;
		const config = req.body as
			| {
					alertWhenValid?: boolean;
			  }
			| undefined;
		const mission = await prisma.mission.findFirstOrThrow({
			where: {
				id: Number(id),
			},
		});

		const activeAircraftinMission = await prisma.connectedAircraft.findFirst({
			where: {
				stationId: {
					in: mission?.missionStationIds,
				},
				posH145active: true,
				logoutTime: null,
			},
			include: {
				Station: true,
			},
		});
		const user = await prisma.user.findFirst({
			where: {
				id: activeAircraftinMission?.userId,
			},
		});

		const clients = await io.in(`desktop:${activeAircraftinMission?.userId}`).fetchSockets();
		if (!clients.length) {
			res.status(400).json({
				error: `Keine Desktop Verbindung für ${user?.publicId} gefunden`,
			});
			return;
		}
		res.json({
			message: "HPG validation started",
		});

		io.to(`desktop:${activeAircraftinMission}`).emit(
			"hpg-validation",
			{
				hpgMissionType: mission?.hpgMissionString,
				lat: mission?.addressLat,
				lng: mission?.addressLng,
			},
			async (result: { state: HpgValidationState; lat: number; lng: number }) => {
				console.log("response from user:", result);

				const newMission = await prisma.mission.update({
					where: { id: Number(id) },
					data: {
						// save position of new mission
						addressLat: result.state === "POSITION_AMANDED" ? result.lat : mission.addressLat,
						addressLng: result.state === "POSITION_AMANDED" ? result.lng : mission.addressLng,
						hpgLocationLat: result.lat,
						hpgLocationLng: result.lng,
						hpgValidationState: result.state,
					},
				});
				io.to("dispatchers").emit("update-mission", newMission);

				const noActionRequired = result.state === "VALID";
				if (noActionRequired) {
					io.to(`user:${req.user?.id}`).emit("notification", {
						type: "hpg-validation",
						status: "success",
						message: `HPG Validierung erfolgreich`,
					} as NotificationPayload);
					if (config?.alertWhenValid) {
						sendAlert(Number(id), {});
					}
				} else {
					io.to(`user:${req.user?.id}`).emit("notification", {
						type: "hpg-validation",
						status: "failed",
						message: `HPG Validation fehlgeschlagen`,
					} as NotificationPayload);
				}
			},
		);
		// TODO: remove this after testing
		setTimeout(() => {
			io.to(`user:${req.user?.id}`).emit("notification", {
				type: "hpg-validation",
				status: "success",
				message: "HPG_BUSY",
				data: {
					mission,
				},
			} as NotificationPayload);
			io.to(`user:${req.user?.id}`).emit("notification", {
				type: "hpg-validation",
				status: "failed",
				message: `HPG Validation fehlgeschlagen`,
				data: {
					mission,
				},
			} as NotificationPayload);
		}, 5000);
	} catch (error) {
		console.error(error);
		res.json({ error: (error as Error).message || "Failed to validate HPG" });
	}
});

export default router;
