import { DateTime } from 'luxon';

/**
 * Converts local date and time string in a specific timezone to a UTC Date object
 * @param localDate YYYY-MM-DD format
 * @param localTime HH:MM format (24h)
 * @param timezone IANA timezone identifier (e.g. Asia/Kolkata)
 */
export function localToUTC(localDateStr: string, localTimeStr: string, timezone: string): Date {
  const dt = DateTime.fromISO(`${localDateStr}T${localTimeStr}`, { zone: timezone });
  if (!dt.isValid) {
    throw new Error(`Invalid local date/time compilation values: ${localDateStr} ${localTimeStr} in ${timezone}`);
  }
  return dt.toJSDate();
}

/**
 * Converts a UTC Date object back to local date and time string in the target timezone
 * @param utcDate Date object
 * @param timezone IANA timezone identifier
 */
export function utcToLocal(utcDate: Date, timezone: string): { localDate: string; localTime: string } {
  const dt = DateTime.fromJSDate(utcDate).setZone(timezone);
  if (!dt.isValid) {
    throw new Error(`Invalid Date or Timezone value: ${utcDate} in ${timezone}`);
  }
  return {
    localDate: dt.toFormat('yyyy-MM-dd'),
    localTime: dt.toFormat('HH:mm')
  };
}

interface OccurrenceResult {
  startDateTime: Date;
  endDateTime: Date;
  localDate: string;
  localTime: string;
}

/**
 * Calculates recurring weekly schedule occurrences between a start and end date
 * @param startDate Starting boundary (e.g. today or schedule startDate)
 * @param endDate Stopping boundary (horizon limit or schedule endDate)
 * @param dayOfWeek 0 (Sunday) to 6 (Saturday)
 * @param localTimeStr HH:MM start time
 * @param localTimeEndStr HH:MM end time
 * @param timezone IANA timezone identifier
 */
export function calculateScheduleOccurrences(
  startDate: Date,
  endDate: Date,
  dayOfWeek: number,
  localTimeStr: string,
  localTimeEndStr: string,
  timezone: string
): OccurrenceResult[] {
  const results: OccurrenceResult[] = [];
  
  // Initialize DateTime boundaries in target timezone
  let current = DateTime.fromJSDate(startDate).setZone(timezone).startOf('day');
  const limit = DateTime.fromJSDate(endDate).setZone(timezone).endOf('day');

  // Luxon: Sunday = 7, Saturday = 6. Mongoose: Sunday = 0, Saturday = 6.
  // Convert Mongoose dayOfWeek to Luxon dayOfWeek (0 -> 7, 1..6 -> 1..6)
  const luxonDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek;

  // Align to first matching day of the week
  let daysDiff = luxonDayOfWeek - current.weekday;
  if (daysDiff < 0) {
    daysDiff += 7;
  }
  current = current.plus({ days: daysDiff });

  // Generate weekly intervals
  while (current <= limit) {
    const localDateStr = current.toFormat('yyyy-MM-dd');
    const startDateTime = localToUTC(localDateStr, localTimeStr, timezone);
    const endDateTime = localToUTC(localDateStr, localTimeEndStr, timezone);

    results.push({
      startDateTime,
      endDateTime,
      localDate: localDateStr,
      localTime: localTimeStr
    });

    current = current.plus({ weeks: 1 });
  }

  return results;
}
