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

const SERVICE_NAME = "statusPageModule";

class StatusPageModule {
	constructor({ StatusPage, NormalizeData, stringService }) {
		this.StatusPage = StatusPage;
		this.NormalizeData = NormalizeData;
		this.stringService = stringService;
	}

	createStatusPage = async ({ statusPageData, image, userId, teamId }) => {
		try {
			const statusPage = new this.StatusPage({
				...statusPageData,
				userId,
				teamId,
			});
			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 = this.stringService.statusPageUrlNotUnique;
			}
			error.service = SERVICE_NAME;
			error.method = "createStatusPage";
			throw error;
		}
	};

	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 this.StatusPage.findOneAndUpdate({ url: statusPageData.url }, statusPageData, {
				new: true,
			});

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

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

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

	getStatusPage = async (url) => {
		try {
			const preliminaryStatusPage = await this.StatusPage.findOne({ url });
			if (!preliminaryStatusPage) {
				const error = new Error(this.stringService.statusPageNotFound);
				error.status = 404;
				throw error;
			}

			if (!preliminaryStatusPage.monitors || preliminaryStatusPage.monitors.length === 0) {
				const { _id, color, companyName, isPublished, logo, originalMonitors, showCharts, showUptimePercentage, timezone, showAdminLoginLink, url } =
					preliminaryStatusPage;
				return {
					statusPage: {
						_id,
						color,
						companyName,
						isPublished,
						logo,
						originalMonitors,
						showCharts,
						showUptimePercentage,
						timezone,
						showAdminLoginLink,
						url,
					},
					monitors: [],
				};
			}

			const statusPageQuery = await this.StatusPage.aggregate([
				{ $match: { url: url } },
				{
					$set: {
						originalMonitors: "$monitors",
					},
				},
				{
					$lookup: {
						from: "monitors",
						localField: "monitors",
						foreignField: "_id",
						as: "monitors",
					},
				},
				{
					$unwind: {
						path: "$monitors",
						preserveNullAndEmptyArrays: true,
					},
				},
				{
					$lookup: {
						from: "maintenancewindows",
						let: { monitorId: "$monitors._id" },
						pipeline: [{ $match: { $expr: { $eq: ["$monitorId", "$$monitorId"] } } }],
						as: "monitors.maintenanceWindows",
					},
				},
				{
					$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"],
						},
						"monitors.isMaintenance": {
							$reduce: {
								input: "$monitors.maintenanceWindows",
								initialValue: false,
								in: {
									$or: [
										"$$value",
										{
											$and: [{ $eq: ["$$this.active", true] }, { $lte: ["$$this.start", "$$NOW"] }, { $gte: ["$$this.end", "$$NOW"] }],
										},
									],
								},
							},
						},
					},
				},
				{ $match: { "monitors.orderIndex": { $ne: -1 } } },
				{ $sort: { "monitors.orderIndex": 1 } },

				{
					$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,
							showAdminLoginLink: 1,
							url: 1,
						},
						monitors: {
							_id: 1,
							userId: 1,
							teamId: 1,
							name: 1,
							description: 1,
							status: 1,
							type: 1,
							ignoreTlsErrors: 1,
							jsonPath: 1,
							expectedValue: 1,
							matchMethod: 1,
							url: 1,
							port: 1,
							isActive: 1,
							interval: 1,
							uptimePercentage: 1,
							notifications: 1,
							secret: 1,
							thresholds: 1,
							alertThreshold: 1,
							cpuAlertThreshold: 1,
							memoryAlertThreshold: 1,
							diskAlertThreshold: 1,
							tempAlertThreshold: 1,
							checks: 1,
							isMaintenance: 1,
							createdAt: 1,
							updatedAt: 1,
						},
					},
				},
			]);
			if (!statusPageQuery.length) {
				const error = new Error(this.stringService.statusPageNotFound);
				error.status = 404;
				throw error;
			}

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

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

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

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

export default StatusPageModule;
