import db from "../db/db.js";
import { RRule, rrulestr } from "rrule";
import { addDays, formatDistanceStrict } from "date-fns";
import type {
  MaintenanceRecord,
  MaintenanceRecordInsert,
  MaintenanceEventRecord,
  MaintenanceEventRecordInsert,
  MaintenanceEventRecordDetailed,
  MaintenanceMonitorRecord,
  MaintenanceFilter,
  MaintenanceEventFilter,
} from "../types/db.js";
import { GetMinuteStartNowTimestampUTC } from "../tool.js";
import { maintenanceToVariables, siteDataToVariables } from "../notification/notification_utils.js";
import { GetAllSiteData } from "./controller.js";
import subscriberQueue from "../queues/subscriberQueue.js";
import GC from "../../global-constants";
import seedSiteData from "../db/seedSiteData.js";

// ============ Input Interfaces ============

export interface MonitorWithStatusInput {
  monitor_tag: string;
  monitor_impact: "UP" | "DOWN" | "DEGRADED" | "MAINTENANCE";
}

export interface CreateMaintenanceInput {
  title: string;
  description?: string | null;
  start_date_time: number; // Unix timestamp - when the first occurrence starts
  rrule: string; // iCalendar RRULE string (e.g., FREQ=WEEKLY;BYDAY=SU or FREQ=MINUTELY;COUNT=1)
  duration_seconds: number; // Duration of each maintenance window in seconds
  // Monitors with their status during maintenance
  monitors?: MonitorWithStatusInput[];
  is_global?: string;
}

export interface UpdateMaintenanceInput {
  title?: string;
  description?: string | null;
  start_date_time?: number;
  rrule?: string;
  duration_seconds?: number;
  status?: "ACTIVE" | "INACTIVE";
  monitors?: MonitorWithStatusInput[];
  is_global?: string;
}

export interface CreateMaintenanceEventInput {
  maintenance_id: number;
  start_date_time: number;
  end_date_time: number;
}

export interface MaintenanceMonitorWithStatus {
  monitor_tag: string;
  monitor_impact: "UP" | "DOWN" | "DEGRADED" | "MAINTENANCE";
}

export interface MaintenanceWithMonitors extends MaintenanceRecord {
  monitors?: MaintenanceMonitorWithStatus[];
}

export interface MaintenanceWithEvents extends MaintenanceWithMonitors {
  events?: MaintenanceEventRecord[];
  upcoming_event?: MaintenanceEventRecord | null;
}

// ============ Helper to determine event status ============

/**
 * Determine the initial status of a maintenance event based on current time
 * - COMPLETED: now >= end_date_time
 * - ONGOING: now >= start_date_time && now < end_date_time
 * - READY: start_date_time - now <= 60 minutes
 * - SCHEDULED: start_date_time - now > 60 minutes
 */
export function determineEventStatus(
  eventStartTimestamp: number,
  eventEndTimestamp: number,
  reminderBufferSeconds: number = 3600,
): "SCHEDULED" | "READY" | "ONGOING" | "COMPLETED" | "CANCELLED" {
  const nowTimestamp = Math.floor(Date.now() / 1000);

  if (nowTimestamp >= eventEndTimestamp) {
    return "COMPLETED";
  }
  if (nowTimestamp >= eventStartTimestamp) {
    return "ONGOING";
  }
  if (eventStartTimestamp - nowTimestamp <= reminderBufferSeconds) {
    return "READY";
  }
  return "SCHEDULED";
}

// ============ Helper to create a maintenance event with notification ============

export const CreateMaintenanceEventWithNotification = async (
  maintenance_id: number,
  start_date_time: number,
  end_date_time: number,
  title: string,
  description: string | null,
): Promise<MaintenanceEventRecord> => {
  const siteData = await GetAllSiteData();
  const notificationSettings =
    siteData.globalMaintenanceNotificationSettings || seedSiteData.globalMaintenanceNotificationSettings;
  const reminderBufferSeconds = notificationSettings.reminder_buffer_hours * 3600;

  const event = await db.createMaintenanceEvent({
    maintenance_id,
    start_date_time,
    end_date_time,
    status: determineEventStatus(start_date_time, end_date_time, reminderBufferSeconds),
  });

  try {
    if (notificationSettings.event_types.created) {
      const siteVars = siteDataToVariables(siteData);
      const siteUrl = siteVars.site_url;
      const monitors = await db.getMonitorsByMaintenanceId(maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");
      const eventDetailed: MaintenanceEventRecordDetailed = {
        id: event.id,
        maintenance_id,
        start_date_time,
        end_date_time,
        status: event.status as MaintenanceEventRecordDetailed["status"],
        created_at: new Date(),
        updated_at: new Date(),
        title,
        description,
      };
      const update = maintenanceToVariables(
        eventDetailed,
        monitorNames,
        "**has been created**",
        "created",
        "Maintenance Created",
        siteUrl,
      );
      await subscriberQueue.push(update);
    }
  } catch (err) {
    console.error(`Error sending created notification for maintenance event ${event.id}:`, err);
  }

  return event;
};

// ============ Helper to generate upcoming events from RRULE ============

/**
 * Generate maintenance events based on the RRULE
 * @param maintenance_id - The maintenance record ID
 * @param start_date_time - Unix timestamp for the DTSTART
 * @param rrule - The RRULE string (e.g., FREQ=WEEKLY;BYDAY=SU)
 * @param duration_seconds - Duration of each maintenance window
 * @param count - Maximum number of events to create (default 1)
 */
export const GenerateMaintenanceEvents = async (
  maintenance_id: number,
  start_date_time: number,
  rrule: string,
  duration_seconds: number,
  count: number = 1,
): Promise<MaintenanceEventRecord[]> => {
  const createdEvents: MaintenanceEventRecord[] = [];

  // Convert start timestamp to Date (UTC)
  const dtstart = new Date(start_date_time * 1000);

  const now = new Date();

  try {
    // Build the full RRULE string with DTSTART
    const fullRrule = `DTSTART:${dtstart.toISOString().replace(/[-:]/g, "").split(".")[0]}Z\nRRULE:${rrule}`;

    // Parse the RRULE
    const rule = rrulestr(fullRrule);

    // Get occurrences based on count
    let occurrences: Date[] = [];

    if (rrule.includes("COUNT=1")) {
      // One-time maintenance: only create event if start_date_time is recent or in the future
      if (dtstart >= now || dtstart >= addDays(now, -1)) {
        occurrences = [dtstart];
      }
    } else {
      // Recurring: get the next `count` occurrences from now
      let searchFrom = now;
      for (let i = 0; i < count; i++) {
        const next = rule.after(searchFrom, i === 0);
        if (!next) break;
        occurrences.push(next);
        searchFrom = new Date(next.getTime() + 1000);
      }
    }

    // Fetch maintenance info for notifications
    const maintenance = await db.getMaintenanceById(maintenance_id);
    const maintenanceTitle = maintenance?.title || "";
    const maintenanceDescription = maintenance?.description || null;

    // Create events for each occurrence
    for (const occurrence of occurrences) {
      const eventStart = Math.floor(occurrence.getTime() / 1000);
      const eventEnd = eventStart + duration_seconds;

      // Check if event already exists for this time
      const existing = await db.getMaintenanceEventsByMaintenanceId(maintenance_id);
      const alreadyExists = existing.some((e) => e.start_date_time === eventStart);

      if (!alreadyExists) {
        const event = await CreateMaintenanceEventWithNotification(
          maintenance_id,
          eventStart,
          eventEnd,
          maintenanceTitle,
          maintenanceDescription,
        );
        createdEvents.push(event);
      }
    }
  } catch (err) {
    console.error("Error generating maintenance events:", err);
  }

  return createdEvents;
};

// ============ Maintenance CRUD ============

export const CreateMaintenance = async (data: CreateMaintenanceInput): Promise<{ maintenance_id: number }> => {
  // Validate required fields
  if (!data.title) {
    throw new Error("Title is required");
  }
  if (!data.start_date_time) {
    throw new Error("Start date/time is required");
  }
  if (!data.rrule) {
    throw new Error("RRULE is required");
  }
  if (!data.duration_seconds || data.duration_seconds <= 0) {
    throw new Error("Duration must be greater than 0");
  }

  // Create the maintenance record
  const maintenance = await db.createMaintenance({
    title: data.title,
    description: data.description || null,
    start_date_time: data.start_date_time,
    rrule: data.rrule,
    duration_seconds: data.duration_seconds,
    status: "ACTIVE",
    is_global: data.is_global || "YES",
  });

  // Add monitors with their status to the maintenance if provided
  if (data.monitors && data.monitors.length > 0) {
    await db.addMonitorsToMaintenanceWithStatus(maintenance.id, data.monitors);
  }

  // Generate initial events
  await GenerateMaintenanceEvents(maintenance.id, data.start_date_time, data.rrule, data.duration_seconds, 1);

  return {
    maintenance_id: maintenance.id,
  };
};

export const GetMaintenanceById = async (id: number): Promise<MaintenanceRecord | undefined> => {
  return await db.getMaintenanceById(id);
};

export const GetMaintenanceWithMonitors = async (id: number): Promise<MaintenanceWithMonitors | null> => {
  const maintenance = await db.getMaintenanceById(id);
  if (!maintenance) return null;

  const monitorRecords = await db.getMaintenanceMonitors(id);

  return {
    ...maintenance,
    monitors: monitorRecords.map((m) => ({ monitor_tag: m.monitor_tag, monitor_impact: m.monitor_impact })),
  };
};

export const GetMaintenanceWithEvents = async (
  id: number,
  pastLimit: number = 5,
  daysInPast: number = 7,
): Promise<MaintenanceWithEvents | null> => {
  const maintenance = await db.getMaintenanceById(id);
  if (!maintenance) return null;

  const now = Math.floor(Date.now() / 1000);
  const events = await db.getMaintenanceEventsByMaintenanceIdWithLimits(id, now, pastLimit, daysInPast);
  const monitorRecords = await db.getMaintenanceMonitors(id);

  // Find the next upcoming or current event (events are sorted by start_date_time asc)
  // Find the first event that hasn't ended yet (ongoing or future)
  const upcomingEvent = events.find((e) => e.end_date_time > now);

  return {
    ...maintenance,
    monitors: monitorRecords.map((m) => ({
      monitor_tag: m.monitor_tag,
      monitor_impact: m.monitor_impact,
    })),
    events,
    upcoming_event: upcomingEvent || null,
  };
};

export const GetMaintenancesDashboard = async (data: {
  page: number;
  limit: number;
  filter?: { status?: string };
}): Promise<{ maintenances: MaintenanceWithEvents[]; total: number }> => {
  const filter: MaintenanceFilter = {};
  if (data.filter?.status && data.filter.status !== "ALL") {
    filter.status = data.filter.status as "ACTIVE" | "INACTIVE";
  }

  const maintenances = await db.getMaintenancesPaginated(data.page, data.limit, filter);
  const totalResult = await db.getMaintenancesCount(filter);
  const total = totalResult ? Number(totalResult.count) : 0;

  // Enrich with events and monitors
  const enriched: MaintenanceWithEvents[] = [];
  for (const m of maintenances) {
    const events = await db.getMaintenanceEventsByMaintenanceId(m.id);
    const monitorRecords = await db.getMaintenanceMonitors(m.id);
    const now = Math.floor(Date.now() / 1000);
    // Find the first event that hasn't ended yet (ongoing or future)
    const upcomingEvent = events.find((e) => e.end_date_time > now);
    enriched.push({
      ...m,
      monitors: monitorRecords.map((mr) => ({
        monitor_tag: mr.monitor_tag,
        monitor_impact: mr.monitor_impact,
      })),
      events,
      upcoming_event: upcomingEvent || null,
    });
  }

  return { maintenances: enriched, total };
};

export const UpdateMaintenance = async (id: number, data: UpdateMaintenanceInput): Promise<number> => {
  const existing = await db.getMaintenanceById(id);
  if (!existing) {
    throw new Error(`Maintenance with id ${id} does not exist`);
  }

  // Extract monitors separately as it's not part of the record
  const { monitors, ...updateData } = data;

  // Determine the rrule after update (use new value if provided, otherwise existing)
  const effectiveRrule = data.rrule !== undefined ? data.rrule : existing.rrule;
  const isOneTime = isOneTimeRrule(effectiveRrule);

  // Check if schedule has changed (start_date_time, rrule, or duration_seconds)
  const scheduleChanged =
    (data.start_date_time !== undefined && data.start_date_time !== existing.start_date_time) ||
    (data.rrule !== undefined && data.rrule !== existing.rrule) ||
    (data.duration_seconds !== undefined && data.duration_seconds !== existing.duration_seconds);

  // Update the maintenance record
  const result = await db.updateMaintenance(id, updateData);

  // Update monitors if provided
  if (monitors !== undefined) {
    await db.removeAllMonitorsFromMaintenance(id);
    if (monitors.length > 0) {
      await db.addMonitorsToMaintenanceWithStatus(id, monitors);
    }
  }

  // Handle schedule changes differently for one-time vs recurring
  if (scheduleChanged) {
    // Get current values (may have been updated)
    const updated = await db.getMaintenanceById(id);
    if (updated) {
      const events = await db.getMaintenanceEventsByMaintenanceId(id);
      const now = Math.floor(Date.now() / 1000);

      if (isOneTime) {
        // For one-time maintenance: delete all events that aren't completed and create a new one
        for (const event of events) {
          // Delete events that are not COMPLETED or CANCELLED
          if (event.status !== "COMPLETED" && event.status !== "CANCELLED") {
            await db.deleteMaintenanceEvent(event.id);
          }
        }
        // Regenerate the event
        await GenerateMaintenanceEvents(id, updated.start_date_time, updated.rrule, updated.duration_seconds, 1);
      } else {
        // For recurring maintenances: delete future SCHEDULED events and regenerate
        for (const event of events) {
          // Only delete SCHEDULED events in the future
          if (event.status === "SCHEDULED" && event.start_date_time > now) {
            await db.deleteMaintenanceEvent(event.id);
          }
        }
        // Regenerate events
        await GenerateMaintenanceEvents(id, updated.start_date_time, updated.rrule, updated.duration_seconds, 1);
      }
    }
  }

  return result;
};

export const DeleteMaintenance = async (id: number): Promise<number> => {
  const existing = await db.getMaintenanceById(id);
  if (!existing) {
    throw new Error(`Maintenance with id ${id} does not exist`);
  }

  return await db.deleteMaintenance(id);
};

// ============ Maintenance Events CRUD ============

export const CreateMaintenanceEvent = async (data: CreateMaintenanceEventInput): Promise<MaintenanceEventRecord> => {
  // Validate maintenance exists
  const maintenance = await db.getMaintenanceById(data.maintenance_id);
  if (!maintenance) {
    throw new Error(`Maintenance with id ${data.maintenance_id} does not exist`);
  }

  // Validate times
  if (data.end_date_time <= data.start_date_time) {
    throw new Error("End date/time must be after start date/time");
  }

  const siteData = await GetAllSiteData();
  const notificationSettings =
    siteData.globalMaintenanceNotificationSettings || seedSiteData.globalMaintenanceNotificationSettings;
  const reminderBufferSeconds = notificationSettings.reminder_buffer_hours * 3600;

  const event = await db.createMaintenanceEvent({
    maintenance_id: data.maintenance_id,
    start_date_time: data.start_date_time,
    end_date_time: data.end_date_time,
    status: determineEventStatus(data.start_date_time, data.end_date_time, reminderBufferSeconds),
  });

  return event;
};

export const GetMaintenanceEventById = async (id: number): Promise<MaintenanceEventRecord | null> => {
  const event = await db.getMaintenanceEventById(id);
  if (!event) return null;
  return event;
};

export const GetMaintenanceEventsByMaintenanceId = async (
  maintenance_id: number,
): Promise<MaintenanceEventRecord[]> => {
  return await db.getMaintenanceEventsByMaintenanceId(maintenance_id);
};

export const UpdateMaintenanceEvent = async (
  id: number,
  data: Partial<MaintenanceEventRecordInsert>,
): Promise<number> => {
  const existing = await db.getMaintenanceEventById(id);
  if (!existing) {
    throw new Error(`Maintenance event with id ${id} does not exist`);
  }

  // Validate times if both provided
  const startTime = data.start_date_time || existing.start_date_time;
  const endTime = data.end_date_time || existing.end_date_time;
  if (endTime <= startTime) {
    throw new Error("End date/time must be after start date/time");
  }

  return await db.updateMaintenanceEvent(id, data);
};

/**
 * Manually transition a maintenance event to a terminal status.
 * Allowed transitions: ONGOING → COMPLETED, SCHEDULED/READY/ONGOING → CANCELLED.
 * An event that already started has its end_date_time moved to the moment it was
 * ended (the record reflects what actually happened); an event that never started
 * keeps its planned window. See docs/adr/0006-manual-maintenance-event-transitions.md
 */
export const UpdateMaintenanceEventStatus = async (id: number, status: string): Promise<MaintenanceEventRecord> => {
  if (status !== GC.COMPLETED && status !== GC.CANCELLED) {
    throw new Error(`Invalid status: ${status}. Allowed values are ${GC.COMPLETED} and ${GC.CANCELLED}`);
  }
  const targetStatus = status as "COMPLETED" | "CANCELLED";

  const existing = await db.getMaintenanceEventById(id);
  if (!existing) {
    throw new Error(`Maintenance event with id ${id} does not exist`);
  }

  const allowedFrom: string[] = targetStatus === GC.COMPLETED ? [GC.ONGOING] : [GC.SCHEDULED, GC.READY, GC.ONGOING];
  if (!allowedFrom.includes(existing.status)) {
    throw new Error(`Cannot transition event from ${existing.status} to ${targetStatus}`);
  }

  if (existing.status === GC.ONGOING) {
    // Ended now, but never before its first minute nor after its planned end
    const endDateTime = Math.min(
      existing.end_date_time,
      Math.max(GetMinuteStartNowTimestampUTC(), existing.start_date_time + 60),
    );
    await db.updateMaintenanceEvent(id, { status: targetStatus, end_date_time: endDateTime });
  } else {
    await db.updateMaintenanceEventStatus(id, targetStatus);
  }

  const updated = await db.getMaintenanceEventById(id);
  if (!updated) {
    throw new Error(`Maintenance event with id ${id} does not exist`);
  }

  try {
    const siteData = await GetAllSiteData();
    const notificationSettings =
      siteData.globalMaintenanceNotificationSettings || seedSiteData.globalMaintenanceNotificationSettings;
    if (notificationSettings.event_types.ended) {
      const siteVars = siteDataToVariables(siteData);
      const siteUrl = siteVars.site_url;
      const maintenance = await db.getMaintenanceById(updated.maintenance_id);
      const monitors = await db.getMonitorsByMaintenanceId(updated.maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");
      const eventDetailed: MaintenanceEventRecordDetailed = {
        ...updated,
        title: maintenance?.title || "",
        description: maintenance?.description || null,
      };
      const update = maintenanceToVariables(
        eventDetailed,
        monitorNames,
        targetStatus === GC.COMPLETED ? "**has been completed**" : "**has been cancelled**",
        targetStatus === GC.COMPLETED ? "completed" : "cancelled",
        targetStatus === GC.COMPLETED ? "Maintenance Completed" : "Maintenance Cancelled",
        siteUrl,
      );
      await subscriberQueue.push(update);
    }
  } catch (err) {
    console.error(`Error sending ${targetStatus} notification for maintenance event ${id}:`, err);
  }

  return updated;
};

export const DeleteMaintenanceEvent = async (id: number): Promise<number> => {
  const existing = await db.getMaintenanceEventById(id);
  if (!existing) {
    throw new Error(`Maintenance event with id ${id} does not exist`);
  }

  return await db.deleteMaintenanceEvent(id);
};

// ============ Maintenance Monitors ============

export const AddMonitorToMaintenance = async (maintenance_id: number, monitor_tag: string): Promise<void> => {
  const maintenance = await db.getMaintenanceById(maintenance_id);
  if (!maintenance) {
    throw new Error(`Maintenance with id ${maintenance_id} does not exist`);
  }

  // Verify monitor exists
  const monitor = await db.getMonitorByTag(monitor_tag);
  if (!monitor) {
    throw new Error(`Monitor with tag ${monitor_tag} does not exist`);
  }

  await db.addMonitorToMaintenance({ maintenance_id, monitor_tag });
};

export const RemoveMonitorFromMaintenance = async (maintenance_id: number, monitor_tag: string): Promise<number> => {
  const maintenance = await db.getMaintenanceById(maintenance_id);
  if (!maintenance) {
    throw new Error(`Maintenance with id ${maintenance_id} does not exist`);
  }

  return await db.removeMonitorFromMaintenance(maintenance_id, monitor_tag);
};

export const GetMaintenanceMonitors = async (
  maintenance_id: number,
): Promise<Array<{ monitor_tag: string; monitor_impact: string }>> => {
  const records = await db.getMaintenanceMonitors(maintenance_id);
  return records.map((r) => ({ monitor_tag: r.monitor_tag, monitor_impact: r.monitor_impact }));
};

export const UpdateMaintenanceMonitorImpact = async (
  maintenance_id: number,
  monitor_tag: string,
  monitor_impact: "UP" | "DOWN" | "DEGRADED" | "MAINTENANCE",
): Promise<number> => {
  const maintenance = await db.getMaintenanceById(maintenance_id);
  if (!maintenance) {
    throw new Error(`Maintenance with id ${maintenance_id} does not exist`);
  }

  // Verify monitor is attached to this maintenance
  const monitors = await db.getMaintenanceMonitors(maintenance_id);
  const monitorExists = monitors.some((m) => m.monitor_tag === monitor_tag);
  if (!monitorExists) {
    throw new Error(`Monitor ${monitor_tag} is not attached to maintenance ${maintenance_id}`);
  }

  return await db.updateMonitorImpactInMaintenanceMonitors(maintenance_id, monitor_tag, monitor_impact);
};

// ============ Status Page Queries ============

export const GetActiveMaintenancesForStatusPage = async (
  start: number,
  end: number,
): Promise<MaintenanceEventRecord[]> => {
  // Get events in the time range
  const events = await db.getActiveMaintenanceEvents(start, end);
  return events;
};

export const GetMaintenanceEventsForMonitor = async (
  monitor_tag: string,
  start: number,
  end: number,
): Promise<MaintenanceEventRecord[]> => {
  return await db.getMaintenanceEventsForMonitor(monitor_tag, start, end);
};

// ============ Helper to check if RRULE is one-time ============
export const isOneTimeRrule = (rrule: string): boolean => {
  // One-time RRULEs typically have COUNT=1
  return rrule.includes("COUNT=1");
};

// ============ Helper to format duration ============
export const formatDurationSeconds = (seconds: number): string => {
  if (seconds < 60) return `${seconds}s`;
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) return `${minutes}m`;
  const hours = Math.floor(minutes / 60);
  const mins = minutes % 60;
  if (mins === 0) return `${hours}h`;
  return `${hours}h ${mins}m`;
};

// ============ Scheduled Status Updates ============

/**
 * Update maintenance event statuses based on current time:
 * 1. SCHEDULED events starting within the reminder buffer → READY
 * 2. READY events where current time is within start/end → ONGOING
 * 3. ONGOING events where end_date_time has passed → COMPLETED
 */
export const UpdateMaintenanceEventStatuses = async (): Promise<void> => {
  const currentTimestamp = GetMinuteStartNowTimestampUTC();
  const siteData = await GetAllSiteData();
  const siteVars = siteDataToVariables(siteData);
  const siteUrl = siteVars.site_url;
  //get global maintenance notification settings
  const notificationSettings =
    siteData.globalMaintenanceNotificationSettings || seedSiteData.globalMaintenanceNotificationSettings;

  const reminderBufferSeconds = notificationSettings.reminder_buffer_hours * 3600;
  try {
    // 1. Mark SCHEDULED events starting within the reminder buffer as READY
    const scheduledEvents = await db.getScheduledEventsStartingSoon(currentTimestamp, reminderBufferSeconds);
    for (const event of scheduledEvents) {
      await db.updateMaintenanceEventStatus(event.id, GC.READY);
      console.log(`Maintenance event ${event.id} marked as READY (starts at ${event.start_date_time})`);
      const monitors = await db.getMonitorsByMaintenanceId(event.maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");
      const timeUntilStart = formatDistanceStrict(
        new Date(event.start_date_time * 1000),
        new Date(currentTimestamp * 1000),
      );
      if (notificationSettings.event_types.reminder) {
        const update = maintenanceToVariables(
          event,
          monitorNames,
          `**is starting in ${timeUntilStart}**`,
          "starting_soon",
          "Maintenance Starting Soon",
          siteUrl,
        );
        await subscriberQueue.push(update);
      }
    }

    // 2. Catch-up: SCHEDULED events that missed the READY window and already started → ONGOING
    const scheduledStartedEvents = await db.getScheduledEventsAlreadyStarted(currentTimestamp);
    for (const event of scheduledStartedEvents) {
      await db.updateMaintenanceEventStatus(event.id, GC.ONGOING);
      console.log(`Maintenance event ${event.id} marked as ONGOING (catch-up from SCHEDULED)`);
      const monitors = await db.getMonitorsByMaintenanceId(event.maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");

      if (notificationSettings.event_types.started) {
        const update = maintenanceToVariables(
          event,
          monitorNames,
          "**is now in progress**",
          "ongoing",
          "Maintenance In Progress",
          siteUrl,
        );
        await subscriberQueue.push(update);
      }
    }

    // 3. Mark READY events that are now in progress as ONGOING
    const readyEvents = await db.getReadyEventsInProgress(currentTimestamp);
    for (const event of readyEvents) {
      await db.updateMaintenanceEventStatus(event.id, GC.ONGOING);
      console.log(`Maintenance event ${event.id} marked as ONGOING`);
      const monitors = await db.getMonitorsByMaintenanceId(event.maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");

      if (notificationSettings.event_types.started) {
        const update = maintenanceToVariables(
          event,
          monitorNames,
          "**is now in progress**",
          "ongoing",
          "Maintenance In Progress",
          siteUrl,
        );
        await subscriberQueue.push(update);
      }
    }

    // 4. Mark ONGOING events that have ended as COMPLETED
    const ongoingEvents = await db.getOngoingEventsCompleted(currentTimestamp);
    for (const event of ongoingEvents) {
      await db.updateMaintenanceEventStatus(event.id, GC.COMPLETED);
      console.log(`Maintenance event ${event.id} marked as COMPLETED`);
      const monitors = await db.getMonitorsByMaintenanceId(event.maintenance_id);
      const monitorNames = monitors.map((m) => `${m.monitor_name}(${m.monitor_impact})`).join(", ");

      if (notificationSettings.event_types.ended) {
        const update = maintenanceToVariables(
          event,
          monitorNames,
          "**has been completed**",
          "completed",
          "Maintenance Completed",
          siteUrl,
        );
        await subscriberQueue.push(update);
      }
    }
  } catch (error) {
    console.error("Error updating maintenance event statuses:", error);
  }
};
