import DistributedUptimeCheck from "../../models/DistributedUptimeCheck.js";
import { ObjectId } from "mongodb";

const SERVICE_NAME = "distributedCheckModule";

const createDistributedCheck = async (checkData) => {
	try {
		if (typeof checkData.monitorId === "string") {
			checkData.monitorId = ObjectId.createFromHexString(checkData.monitorId);
		}
		const check = await DistributedUptimeCheck.findOneAndUpdate(
			{
				monitorId: checkData.monitorId,
				city: checkData.city,
			},
			[
				{
					$set: {
						...checkData,

						responseTime: {
							$cond: {
								if: { $ifNull: ["$count", false] },
								then: {
									$cond: {
										// Check if the new value is an outlier (3x the current average)
										if: {
											$and: [
												{ $gt: ["$responseTime", 0] },
												{
													$gt: [
														checkData.responseTime,
														{ $multiply: ["$responseTime", 3] },
													],
												},
											],
										},
										then: "$responseTime", // Keep the current value if it's an outlier
										else: {
											// Normal case - calculate new average
											$round: [
												{
													$divide: [
														{
															$add: [
																{ $multiply: ["$responseTime", "$count"] },
																checkData.responseTime,
															],
														},
														{ $add: ["$count", 1] },
													],
												},
												2,
											],
										},
									},
								},
								else: checkData.responseTime,
							},
						},
						count: { $add: [{ $ifNull: ["$count", 0] }, 1] },
					},
				},
			],
			{
				upsert: true,
				new: true,
				runValidators: true,
			}
		);
		return check;
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "createCheck";
		throw error;
	}
};

const createDistributedChecks = async (checksData) => {
	try {
		if (!Array.isArray(checksData) || checksData.length === 0) {
			return;
		}

		const bulkOps = checksData.map((checkData) => {
			if (typeof checkData.monitorId === "string") {
				checkData.monitorId = ObjectId.createFromHexString(checkData.monitorId);
			}

			return {
				updateOne: {
					filter: {
						monitorId: checkData.monitorId,
						city: checkData.city,
					},
					update: [
						{
							$set: {
								...checkData,
								responseTime: {
									$cond: {
										if: { $ifNull: ["$count", false] },
										then: {
											$round: [
												{
													$divide: [
														{
															$add: [
																{ $multiply: ["$responseTime", "$count"] },
																checkData.responseTime,
															],
														},
														{ $add: ["$count", 1] },
													],
												},
												2,
											],
										},
										else: checkData.responseTime,
									},
								},
								count: { $add: [{ $ifNull: ["$count", 0] }, 1] },
							},
						},
					],
					upsert: true,
				},
			};
		});

		await DistributedUptimeCheck.bulkWrite(bulkOps, {
			ordered: false,
		});
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "createDistributedChecks";
		throw error;
	}
};

const deleteDistributedChecksByMonitorId = async (monitorId) => {
	try {
		const result = await DistributedUptimeCheck.deleteMany({ monitorId });
		return result.deletedCount;
	} catch (error) {
		error.service = SERVICE_NAME;
		error.method = "deleteDistributedChecksByMonitorId";
		throw error;
	}
};

export {
	createDistributedCheck,
	createDistributedChecks,
	deleteDistributedChecksByMonitorId,
};
