import { sendEventNotification } from "./notification";
import Event from "../models/event";

// In-memory scheduler (replaces Bull/Redis). Timers are lost on restart,
// so upcoming events are re-scheduled from the database at startup.
const MAX_TIMEOUT = 2 ** 31 - 1;
const timers = new Map<string, NodeJS.Timeout>();

function arm(eventId: string, delay: number) {
  const wait = Math.min(Math.max(delay, 0), MAX_TIMEOUT);
  const timer = setTimeout(async () => {
    timers.delete(eventId);
    if (delay > MAX_TIMEOUT) return arm(eventId, delay - MAX_TIMEOUT);
    try {
      const event = await Event.findById(eventId);
      if (!event) return;
      sendEventNotification(event);
    } catch (err) {
      console.error("Scheduled notification failed", err);
    }
  }, wait);
  timers.set(eventId, timer);
}

export function scheduleEvent(event: any) {
  const id = event._id.toString();
  clearTimeout(timers.get(id));
  arm(id, calculateDelayUntilEvent(event.fullDate, event.time));
}

export async function updateScheduledEvent(event: any) {
  scheduleEvent(event);
}

export async function deleteScheduledEvent(event: any) {
  const id = event._id.toString();
  clearTimeout(timers.get(id));
  timers.delete(id);
}

export async function rescheduleUpcomingEvents() {
  const events: any[] = await Event.find({ fullDate: { $gte: new Date() } });
  events.forEach((event: any) => scheduleEvent(event));
  console.log(`Rescheduled ${events.length} upcoming events`);
}

function calculateDelayUntilEvent(eventDate: any, eventTime: any) {
  const eventDateTime = new Date(eventDate);
  eventDateTime.setHours(eventTime.getHours(), eventTime.getMinutes(), 0, 0);
  return eventDateTime.getTime() - Date.now();
}
