import StatusPage from "../../models/StatusPage.js";
import Monitor from "../../models/Monitor.js";
import { NormalizeData } from "../../../utils/dataUtils.js";
import ServiceRegistry from "../../../service/serviceRegistry.js";
import StringService from "../../../service/stringService.js";

const SERVICE_NAME = "statusPageModule";

const createStatusPage = async (statusPageData, image) => {
	const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);

	try {
		const statusPage = new StatusPage({ ...statusPageData });
		if (image) {
			statusPage.logo = {
				data: image.buffer,
				contentType: image.mimetype,
			};
		}
		await statusPage.save();
		return statusPage;
	} catch (error) {
		if (error?.code === 11000) {
			// Handle duplicate URL errors
			error.status = 400;
			error.message = stringService.statusPageUrlNotUnique;
		}
		error.service = SERVICE_NAME;
		error.method = "createStatusPage";
		throw error;
	}
};

const updateStatusPage = async (statusPageData, image) => {
	try {
		if (image) {
			statusPageData.logo = {
				data: image.buffer,
				contentType: image.mimetype,
			};
		} else {
			statusPageData.logo = null;
		}

		if (statusPageData.deleteSubmonitors === "true") {
			statusPageData.subMonitors = [];
		}
		const statusPage = await StatusPage.findOneAndUpdate(
			{ url: statusPageData.url },
			statusPageData,
			{
				new: true,
			}
		);

		return statusPage;
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "updateStatusPage";
		throw error;
	}
};

const getStatusPageByUrl = async (url, type) => {
	// TODO This is deprecated, can remove and have controller call getStatusPage
	try {
		return getStatusPage(url);
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "getStatusPageByUrl";
		throw error;
	}
};

const getStatusPagesByTeamId = async (teamId) => {
	try {
		const statusPages = await StatusPage.find({ teamId });
		return statusPages;
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "getStatusPagesByTeamId";
		throw error;
	}
};

const getStatusPage = async (url) => {
	const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);

	try {
		const statusPageQuery = await StatusPage.aggregate([
			{ $match: { url: url } },
			{
				$set: {
					originalMonitors: "$monitors",
				},
			},
			{
				$lookup: {
					from: "monitors",
					localField: "monitors",
					foreignField: "_id",
					as: "monitors",
				},
			},
			{
				$unwind: "$monitors",
			},
			{
				$lookup: {
					from: "checks",
					let: { monitorId: "$monitors._id" },
					pipeline: [
						{
							$match: {
								$expr: { $eq: ["$monitorId", "$$monitorId"] },
							},
						},
						{ $sort: { createdAt: -1 } },
						{ $limit: 25 },
					],
					as: "monitors.checks",
				},
			},
			{
				$addFields: {
					"monitors.orderIndex": {
						$indexOfArray: ["$originalMonitors", "$monitors._id"],
					},
				},
			},
			{
				$group: {
					_id: "$_id",
					statusPage: { $first: "$$ROOT" },
					monitors: { $push: "$monitors" },
				},
			},
			{
				$project: {
					statusPage: {
						_id: 1,
						color: 1,
						companyName: 1,
						isPublished: 1,
						logo: 1,
						originalMonitors: 1,
						showCharts: 1,
						showUptimePercentage: 1,
						timezone: 1,
						url: 1,
					},
					monitors: {
						$sortArray: {
							input: "$monitors",
							sortBy: { orderIndex: 1 },
						},
					},
				},
			},
		]);
		if (!statusPageQuery.length) {
			const error = new Error(stringService.statusPageNotFound);
			error.status = 404;
			throw error;
		}

		const { statusPage, monitors } = statusPageQuery[0];

		const normalizedMonitors = monitors.map((monitor) => {
			return {
				...monitor,
				checks: NormalizeData(monitor.checks, 10, 100),
			};
		});

		return { statusPage, monitors: normalizedMonitors };
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "getStatusPageByUrl";
		throw error;
	}
};

const deleteStatusPage = async (url) => {
	try {
		await StatusPage.deleteOne({ url });
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "deleteStatusPage";
		throw error;
	}
};

const deleteStatusPagesByMonitorId = async (monitorId) => {
	try {
		await StatusPage.deleteMany({ monitors: { $in: [monitorId] } });
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "deleteStatusPageByMonitorId";
		throw error;
	}
};

export {
	createStatusPage,
	updateStatusPage,
	getStatusPagesByTeamId,
	getStatusPage,
	getStatusPageByUrl,
	deleteStatusPage,
	deleteStatusPagesByMonitorId,
};
