import dayjs, { Dayjs } from 'dayjs';
import { TAT_CONFIG, isTestMode } from '../config/tat.config';

// Cache for holidays to avoid repeated DB queries
let holidaysCache: Set<string> = new Set();
let holidaysCacheExpiry: Date | null = null;

// Cache for working hours configuration
interface WorkingHoursConfig {
  startHour: number;
  endHour: number;
  startDay: number;
  endDay: number;
}

let workingHoursCache: WorkingHoursConfig | null = null;
let workingHoursCacheExpiry: Date | null = null;

/**
 * Load working hours configuration from database and cache them
 */
async function loadWorkingHoursCache(): Promise<void> {
  try {
    // Reload cache every 5 minutes (shorter than holidays since it's more important)
    if (workingHoursCacheExpiry && new Date() < workingHoursCacheExpiry) {
      return;
    }

    const { getWorkingHours, getConfigNumber } = await import('../services/configReader.service');
    const hours = await getWorkingHours();
    const startDay = await getConfigNumber('WORK_START_DAY', 1); // Monday
    const endDay = await getConfigNumber('WORK_END_DAY', 5); // Friday

    workingHoursCache = {
      startHour: hours.startHour,
      endHour: hours.endHour,
      startDay: startDay,
      endDay: endDay
    };
    workingHoursCacheExpiry = dayjs().add(5, 'minute').toDate();
  } catch (error) {
    workingHoursCache = {
      startHour: TAT_CONFIG.WORK_START_HOUR,
      endHour: TAT_CONFIG.WORK_END_HOUR,
      startDay: TAT_CONFIG.WORK_START_DAY,
      endDay: TAT_CONFIG.WORK_END_DAY
    };
  }
}

/**
 * Load holidays from database and cache them
 */
async function loadHolidaysCache(): Promise<void> {
  try {
    // Reload cache every 6 hours
    if (holidaysCacheExpiry && new Date() < holidaysCacheExpiry) {
      return;
    }

    const { holidayService } = await import('../services/holiday.service');
    const currentYear = new Date().getFullYear();
    const startDate = `${currentYear}-01-01`;
    const endDate = `${currentYear + 1}-12-31`; // Include next year for year-end calculations

    const holidays = await holidayService.getHolidaysInRange(startDate, endDate);
    holidaysCache = new Set(holidays);
    holidaysCacheExpiry = dayjs().add(6, 'hour').toDate();

  } catch (error) {
    console.error('[TAT] Error loading holidays:', error);
    // Continue without holidays if loading fails
  }
}

/**
 * Check if a date is a holiday (uses cache)
 */
function isHoliday(date: Dayjs): boolean {
  const dateStr = date.format('YYYY-MM-DD');
  return holidaysCache.has(dateStr);
}

/**
 * Check if a given date is within working time
 * Working hours: Configured in admin settings (default: Monday-Friday, 9 AM - 6 PM)
 * Excludes: Weekends (Sat/Sun) and holidays
 * In TEST MODE: All times are considered working time
 */
function isWorkingTime(date: Dayjs): boolean {
  // In test mode, treat all times as working time for faster testing
  if (isTestMode()) {
    return true;
  }

  // Use cached working hours (with fallback to TAT_CONFIG)
  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  const day = date.day(); // 0 = Sun, 6 = Sat
  const hour = date.hour();

  // Check if weekend (based on configured working days)
  if (day < config.startDay || day > config.endDay) {
    return false;
  }

  // Check if outside working hours (based on configured hours)
  if (hour < config.startHour || hour >= config.endHour) {
    return false;
  }

  // Check if holiday
  if (isHoliday(date)) {
    return false;
  }

  return true;
}

/**
 * Add working hours to a start date (STANDARD mode)
 * Skips weekends, non-working hours, and holidays (unless in test mode)
 * Uses dynamic working hours from admin configuration
 * In TEST MODE: 1 hour = 1 minute for faster testing
 */
export async function addWorkingHours(start: Date | string, hoursToAdd: number): Promise<Dayjs> {
  let current = dayjs(start);

  // In test mode, convert hours to minutes for faster testing
  if (isTestMode()) {
    return current.add(hoursToAdd, 'minute');
  }

  // Load working hours and holidays cache if not loaded
  await loadWorkingHoursCache();
  await loadHolidaysCache();

  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  // If start time is before working hours or outside working days/holidays,
  // advance to the next working hour start (reset to clean hour)
  const originalStart = current.format('YYYY-MM-DD HH:mm:ss');
  const wasOutsideWorkingHours = !isWorkingTime(current);

  while (!isWorkingTime(current)) {
    const hour = current.hour();
    const day = current.day();

    // If before work start hour on a working day, jump to work start hour
    if (day >= config.startDay && day <= config.endDay && !isHoliday(current) && hour < config.startHour) {
      current = current.hour(config.startHour);
    } else {
      // After working hours or non-working day - advance to next working period
      current = current.add(1, 'hour');
    }
  }

  // If start time was outside working hours, reset to clean work start time (no minutes)
  if (wasOutsideWorkingHours) {
    current = current.minute(0).second(0).millisecond(0);
  }

  // Split into whole hours and fractional part
  const wholeHours = Math.floor(hoursToAdd);
  const fractionalHours = hoursToAdd - wholeHours;

  let remaining = wholeHours;

  // Add whole hours
  while (remaining > 0) {
    current = current.add(1, 'hour');
    if (isWorkingTime(current)) {
      remaining -= 1;
    }
  }

  // Add fractional part (convert to minutes)
  if (fractionalHours > 0) {
    const minutesToAdd = Math.round(fractionalHours * 60);
    current = current.add(minutesToAdd, 'minute');

    // Check if fractional addition pushed us outside working time
    if (!isWorkingTime(current)) {
      // Advance to next working period
      while (!isWorkingTime(current)) {
        current = current.add(1, 'hour');
        const hour = current.hour();
        const day = current.day();

        // If before work start hour on a working day, jump to work start hour
        if (day >= config.startDay && day <= config.endDay && !isHoliday(current) && hour < config.startHour) {
          current = current.hour(config.startHour).minute(0).second(0).millisecond(0);
        }
      }
    }
  }

  return current;
}

/**
 * Add working hours for EXPRESS priority
 * Includes ALL days (weekends, holidays) but only counts working hours (9 AM - 6 PM)
 * @param start - Start date/time
 * @param hoursToAdd - Hours to add
 * @returns Deadline date
 */
export async function addWorkingHoursExpress(start: Date | string, hoursToAdd: number): Promise<Dayjs> {
  let current = dayjs(start);

  // In test mode, convert hours to minutes for faster testing
  if (isTestMode()) {
    return current.add(hoursToAdd, 'minute');
  }

  // Load configuration (but don't load holidays - EXPRESS works on holidays too)
  await loadWorkingHoursCache();

  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  // If start time is outside working hours, advance to work start hour (reset to clean hour)
  // IMPORTANT: For EXPRESS, we work on ALL days (weekends, holidays), so we don't skip them
  const originalStart = current.format('YYYY-MM-DD HH:mm:ss');
  const currentHour = current.hour();
  const currentDay = current.day(); // 0 = Sunday, 6 = Saturday

  if (currentHour < config.startHour) {
    // Before work hours - jump to work start hour on the same day (even if weekend/holiday)
    current = current.hour(config.startHour).minute(0).second(0).millisecond(0);
  } else if (currentHour >= config.endHour) {
    // After work hours - go to next day's work start hour (even if weekend/holiday)
    current = current.add(1, 'day').hour(config.startHour).minute(0).second(0).millisecond(0);
  }

  // Split into whole hours and fractional part
  const wholeHours = Math.floor(hoursToAdd);
  const fractionalHours = hoursToAdd - wholeHours;

  let remaining = wholeHours;
  let hoursCounted = 0;

  // Add whole hours
  //: For EXPRESS, count ALL days (weekends, holidays) - only check working hours (9 AM - 6 PM)
  let iterations = 0;
  const maxIterations = 10000; // Safety limit

  while (remaining > 0 && iterations < maxIterations) {
    current = current.add(1, 'hour');
    const hour = current.hour();

    // For express: count ALL days (including weekends/holidays)
    // But only during working hours (configured start - end hour)
    // NO checks for day of week or holidays - EXPRESS works 7 days a week
    if (hour >= config.startHour && hour < config.endHour) {
      remaining -= 1;
    }
    // If outside working hours, we just continue to next hour without counting
    // This ensures we only count 9 AM - 6 PM on any day
    iterations++;
  }

  if (iterations >= maxIterations) {
    console.error(`[EXPRESS TAT] Safety break - exceeded ${maxIterations} iterations`);
  }

  // Add fractional part (convert to minutes)
  if (fractionalHours > 0) {
    const minutesToAdd = Math.round(fractionalHours * 60);
    current = current.add(minutesToAdd, 'minute');

    // Check if fractional addition pushed us past working hours
    if (current.hour() >= config.endHour) {
      // Overflow to next day's working hours (even if weekend/holiday)
      const excessMinutes = (current.hour() - config.endHour) * 60 + current.minute();
      current = current.add(1, 'day').hour(config.startHour).minute(excessMinutes).second(0).millisecond(0);
    }
  }

  return current;
}

/**
 * Add calendar hours (24/7, no exclusions) - DEPRECATED
 * @deprecated Use addWorkingHoursExpress() for express priority
 */
export function addCalendarHours(start: Date | string, hoursToAdd: number): Dayjs {
  let current = dayjs(start);

  // In test mode, convert hours to minutes for faster testing
  if (isTestMode()) {
    return current.add(hoursToAdd, 'minute');
  }

  // Simply add hours without any exclusions (24/7)
  return current.add(hoursToAdd, 'hour');
}

/**
 * Synchronous version for backward compatibility (doesn't check holidays)
 * Use addWorkingHours() for holiday-aware calculations
 * @deprecated Use async addWorkingHours() instead for accurate calculations
 */
export function addWorkingHoursSync(start: Date | string, hoursToAdd: number): Dayjs {
  let current = dayjs(start);

  // In test mode, convert hours to minutes for faster testing
  if (isTestMode()) {
    return current.add(hoursToAdd, 'minute');
  }

  // Use cached working hours with fallback
  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  // If start time is before working hours or outside working days,
  // advance to the next working hour start (reset to clean hour)
  const originalStart = current.format('YYYY-MM-DD HH:mm:ss');
  let hour = current.hour();
  let day = current.day();

  // Check if originally outside working hours
  const wasOutsideWorkingHours = !(day >= config.startDay && day <= config.endDay && hour >= config.startHour && hour < config.endHour);

  // If before work start hour on a working day, jump to work start hour
  if (day >= config.startDay && day <= config.endDay && hour < config.startHour) {
    current = current.hour(config.startHour);
  } else {
    // Advance to next working hour
    while (!(day >= config.startDay && day <= config.endDay && hour >= config.startHour && hour < config.endHour)) {
      current = current.add(1, 'hour');
      day = current.day();
      hour = current.hour();
    }
  }

  // If start time was outside working hours, reset to clean work start time
  if (wasOutsideWorkingHours) {
    current = current.minute(0).second(0).millisecond(0);
  }

  let remaining = hoursToAdd;

  while (remaining > 0) {
    current = current.add(1, 'hour');
    const day = current.day();
    const hour = current.hour();
    // Simple check without holidays (but respects configured working hours)
    if (day >= config.startDay && day <= config.endDay &&
      hour >= config.startHour && hour < config.endHour) {
      remaining -= 1;
    }
  }

  return current;
}

/**
 * Initialize holidays and working hours cache (call on server startup)
 */
export async function initializeHolidaysCache(): Promise<void> {
  await loadWorkingHoursCache();
  await loadHolidaysCache();
}

/**
 * Clear working hours cache (call when admin updates configuration)
 * Also immediately reloads the cache with new values
 */
export async function clearWorkingHoursCache(): Promise<void> {
  workingHoursCache = null;
  workingHoursCacheExpiry = null;

  // Immediately reload the cache with new values
  await loadWorkingHoursCache();
}

/**
 * Calculate TAT milestones (50%, 75%, 100%)
 * Returns Date objects for each milestone
 * Async version - honors holidays
 */
export async function calculateTatMilestones(start: Date | string, tatDurationHours: number) {
  const halfTime = await addWorkingHours(start, tatDurationHours * 0.5);
  const seventyFive = await addWorkingHours(start, tatDurationHours * 0.75);
  const full = await addWorkingHours(start, tatDurationHours);

  return {
    halfTime: halfTime.toDate(),
    seventyFive: seventyFive.toDate(),
    full: full.toDate()
  };
}

/**
 * Synchronous version for backward compatibility (doesn't check holidays)
 */
export function calculateTatMilestonesSync(start: Date | string, tatDurationHours: number) {
  const halfTime = addWorkingHoursSync(start, tatDurationHours * 0.5);
  const seventyFive = addWorkingHoursSync(start, tatDurationHours * 0.75);
  const full = addWorkingHoursSync(start, tatDurationHours);

  return {
    halfTime: halfTime.toDate(),
    seventyFive: seventyFive.toDate(),
    full: full.toDate()
  };
}

/**
 * Calculate delay in milliseconds from now to target date
 */
export function calculateDelay(targetDate: Date): number {
  const now = dayjs();
  const target = dayjs(targetDate);
  const delay = target.diff(now, 'millisecond');
  return delay > 0 ? delay : 0; // Return 0 if target is in the past
}

/**
 * Check if current time is within working hours
 * @returns true if currently in working hours, false if paused
 */
export async function isCurrentlyWorkingTime(priority: string = 'standard'): Promise<boolean> {
  await loadWorkingHoursCache();
  await loadHolidaysCache();

  const now = dayjs();

  // In test mode, always working time
  if (isTestMode()) {
    return true;
  }

  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  const day = now.day();
  const hour = now.hour();
  const dateStr = now.format('YYYY-MM-DD');

  // Check working hours
  const isWorkingHour = hour >= config.startHour && hour < config.endHour;

  // For express: include weekends, for standard: exclude weekends
  const isWorkingDay = priority === 'express'
    ? true
    : (day >= config.startDay && day <= config.endDay);

  // Check if not a holiday
  const isNotHoliday = !holidaysCache.has(dateStr);

  return isWorkingDay && isWorkingHour && isNotHoliday;
}

/**
 * Calculate comprehensive SLA status for an approval level
 * Returns all data needed for frontend display
 */
export async function calculateSLAStatus(
  levelStartTime: Date | string,
  tatHours: number,
  priority: string = 'standard',
  endDate?: Date | string | null,
  pauseInfo?: { isPaused: boolean; pausedAt?: Date | string | null; pauseElapsedHours?: number; pauseResumeDate?: Date | string | null }
) {
  await loadWorkingHoursCache();
  await loadHolidaysCache();

  const startDate = dayjs(levelStartTime);
  // Use provided endDate if available (for completed requests), otherwise use current time
  const endTime = endDate ? dayjs(endDate) : dayjs();

  // Calculate elapsed working hours (with pause handling)
  const elapsedHours = await calculateElapsedWorkingHours(levelStartTime, endTime.toDate(), priority, pauseInfo);
  const remainingHours = Math.max(0, tatHours - elapsedHours);
  const percentageUsed = tatHours > 0 ? Math.min(100, Math.round((elapsedHours / tatHours) * 100)) : 0;

  // Calculate deadline based on priority
  // EXPRESS: All days (Mon-Sun) but working hours only (9 AM - 6 PM)
  // STANDARD: Weekdays only (Mon-Fri) and working hours (9 AM - 6 PM)
  // If paused, adjust deadline calculation to account for pause time
  let deadline: Date;
  if (pauseInfo?.isPaused && pauseInfo.pauseElapsedHours !== undefined) {
    // If paused, deadline should be calculated from original start + TAT
    // But we need to account for the pause duration
    const remainingTatAfterPause = tatHours - pauseInfo.pauseElapsedHours;
    if (pauseInfo.pauseResumeDate) {
      // Calculate deadline from resume date with remaining TAT
      deadline = priority === 'express'
        ? (await addWorkingHoursExpress(pauseInfo.pauseResumeDate, remainingTatAfterPause)).toDate()
        : (await addWorkingHours(pauseInfo.pauseResumeDate, remainingTatAfterPause)).toDate();
    } else {
      // Still paused, use original calculation
      deadline = priority === 'express'
        ? (await addWorkingHoursExpress(levelStartTime, tatHours)).toDate()
        : (await addWorkingHours(levelStartTime, tatHours)).toDate();
    }
  } else {
    deadline = priority === 'express'
      ? (await addWorkingHoursExpress(levelStartTime, tatHours)).toDate()
      : (await addWorkingHours(levelStartTime, tatHours)).toDate();
  }

  // Check if currently paused (workflow pause or outside working hours)
  // For completed requests (with endDate), it's not paused
  const isPaused = endDate
    ? false
    : (pauseInfo?.isPaused === true || !(await isCurrentlyWorkingTime(priority)));

  // Determine status
  let status: 'on_track' | 'approaching' | 'critical' | 'breached' = 'on_track';
  if (percentageUsed >= 100) {
    status = 'breached';
  } else if (percentageUsed >= 80) {
    status = 'critical';
  } else if (percentageUsed >= 60) {
    status = 'approaching';
  }

  // Format remaining time
  const formatTime = (hours: number) => {
    if (hours <= 0) return '0h';
    const days = Math.floor(hours / 8); // 8 working hours per day
    const remainingHrs = Math.floor(hours % 8);
    const minutes = Math.round((hours % 1) * 60);

    if (days > 0) {
      return minutes > 0
        ? `${days}d ${remainingHrs}h ${minutes}m`
        : `${days}d ${remainingHrs}h`;
    }
    return minutes > 0 ? `${remainingHrs}h ${minutes}m` : `${remainingHrs}h`;
  };

  return {
    elapsedHours: Math.round(elapsedHours * 100) / 100,
    remainingHours: Math.round(remainingHours * 100) / 100,
    percentageUsed,
    deadline: deadline.toISOString(),
    isPaused,
    status,
    remainingText: formatTime(remainingHours),
    elapsedText: formatTime(elapsedHours)
  };
}

/**
 * Calculate elapsed working hours between two dates
 * Uses minute-by-minute precision to accurately count only working time
 * @param startDate - Start time (when level was assigned)
 * @param endDate - End time (defaults to now)
 * @param priority - 'express' or 'standard' (express includes weekends, standard excludes)
 * @param pauseInfo - Optional pause information { isPaused: boolean, pausedAt?: Date, pauseElapsedHours?: number, pauseResumeDate?: Date }
 * @returns Elapsed working hours (with decimal precision)
 */
export async function calculateElapsedWorkingHours(
  startDate: Date | string,
  endDateParam: Date | string | null = null,
  priority: string = 'standard',
  pauseInfo?: { isPaused: boolean; pausedAt?: Date | string | null; pauseElapsedHours?: number; pauseResumeDate?: Date | string | null }
): Promise<number> {
  await loadWorkingHoursCache();
  await loadHolidaysCache();

  // Handle pause: if paused, use elapsed hours at pause time
  if (pauseInfo?.isPaused && pauseInfo.pauseElapsedHours !== undefined) {
    // If currently paused, return the elapsed hours at pause time
    // No additional time accumulates while paused
    return pauseInfo.pauseElapsedHours;
  }

  // If was paused but now resumed, calculate from resume date
  let actualStartDate = startDate;
  let prePauseElapsed = 0;
  let resumeTime = null;

  if (pauseInfo?.pauseResumeDate && pauseInfo.pauseElapsedHours !== undefined) {
    // Was paused, now resumed
    // Use elapsed hours at pause + time from resume to end
    prePauseElapsed = pauseInfo.pauseElapsedHours;
    actualStartDate = pauseInfo.pauseResumeDate;
    resumeTime = pauseInfo.pauseResumeDate; // Store resume time for reference
  }

  let start = dayjs(actualStartDate);
  const end = dayjs(endDateParam || new Date());

  // In test mode, use raw minutes for 1:1 conversion
  if (isTestMode()) {
    const postResumeHours = end.diff(start, 'minute') / 60;
    return prePauseElapsed + postResumeHours;
  }

  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  //: For resumed levels, we must use the exact resume time as start
  // Do NOT advance resume time to next working period - resume time is the actual moment TAT resumed
  // Only advance if we're calculating from original start (not resumed)
  const isResumedLevel = resumeTime !== null;

  if (!isResumedLevel) {
    // Only adjust start time if this is NOT a resumed level
    // For resumed levels, use exact resume time (even if outside working hours)
    // The working hours calculation below will handle skipping non-working periods

    // FIX: If start time is outside working hours, advance to next working period
    // This ensures we only count elapsed time when TAT is actually running
    const originalStart = start.format('YYYY-MM-DD HH:mm:ss');

    // For standard priority, check working days and hours
    if (priority !== 'express') {
      const wasOutsideWorkingHours = !isWorkingTime(start);

      while (!isWorkingTime(start)) {
        const hour = start.hour();
        const day = start.day();

        // If before work start hour on a working day, jump to work start hour
        if (day >= config.startDay && day <= config.endDay && !isHoliday(start) && hour < config.startHour) {
          start = start.hour(config.startHour);
        } else {
          // Otherwise, advance by 1 hour and check again
          start = start.add(1, 'hour');
        }
      }

      // If start time was outside working hours, reset to clean work start time
      if (wasOutsideWorkingHours) {
        start = start.minute(0).second(0).millisecond(0);
      }
    } else {
      // For express priority, only check working hours (not days)
      const hour = start.hour();
      if (hour < config.startHour) {
        // Before hours - reset to clean start
        start = start.hour(config.startHour).minute(0).second(0).millisecond(0);
      } else if (hour >= config.endHour) {
        // After hours - reset to clean start of next day
        start = start.add(1, 'day').hour(config.startHour).minute(0).second(0).millisecond(0);
      }
    }
  }
  // For resumed levels, keep the exact resume time - the day-by-day calculation below will handle working hours correctly

  if (end.isBefore(start)) {
    return 0;
  }

  let totalWorkingMinutes = 0;
  let currentDate = start.startOf('day');
  const endDay = end.startOf('day');

  // Process each day
  while (currentDate.isBefore(endDay) || currentDate.isSame(endDay, 'day')) {
    const dateStr = currentDate.format('YYYY-MM-DD');
    const dayOfWeek = currentDate.day();

    // Check if this day is a working day
    const isWorkingDay = priority === 'express'
      ? true
      : (dayOfWeek >= config.startDay && dayOfWeek <= config.endDay);
    const isNotHoliday = !holidaysCache.has(dateStr);

    if (isWorkingDay && isNotHoliday) {
      // Determine the working period for this day
      let dayStart = currentDate.hour(config.startHour).minute(0).second(0);
      let dayEnd = currentDate.hour(config.endHour).minute(0).second(0);

      // Adjust for first day (might start mid-day)
      if (currentDate.isSame(start, 'day')) {
        if (start.hour() >= config.endHour) {
          // Started after work hours - skip this day
          currentDate = currentDate.add(1, 'day');
          continue;
        } else if (start.hour() >= config.startHour) {
          // Started during work hours - use actual start time
          dayStart = start;
        }
        // If before work hours, dayStart is already correct (work start time)
      }

      // Adjust for last day (might end mid-day)
      if (currentDate.isSame(end, 'day')) {
        if (end.hour() < config.startHour) {
          // Ended before work hours - skip this day
          currentDate = currentDate.add(1, 'day');
          continue;
        } else if (end.hour() < config.endHour) {
          // Ended during work hours - use actual end time
          dayEnd = end;
        }
        // If after work hours, dayEnd is already correct (work end time)
      }

      // Calculate minutes worked this day
      if (dayStart.isBefore(dayEnd)) {
        const minutesThisDay = dayEnd.diff(dayStart, 'minute');
        totalWorkingMinutes += minutesThisDay;
      }
    }

    currentDate = currentDate.add(1, 'day');

    // Safety check
    if (currentDate.diff(start, 'day') > 730) { // 2 years
      console.error('[TAT] Safety break - exceeded 2 years');
      break;
    }
  }

  const hours = totalWorkingMinutes / 60;

  // Add pre-pause elapsed hours if resumed
  return prePauseElapsed + hours;
}

/**
 * Calculate business days between two dates
 * Excludes weekends and holidays
 * @param startDate - Start date
 * @param endDate - End date (defaults to now)
 * @param priority - 'express' or 'standard' (express includes weekends, standard excludes)
 * @returns Number of business days
 */
export async function calculateBusinessDays(
  startDate: Date | string,
  endDate: Date | string | null = null,
  priority: string = 'standard'
): Promise<number> {
  await loadWorkingHoursCache();
  await loadHolidaysCache();

  let start = dayjs(startDate).startOf('day');
  const end = dayjs(endDate || new Date()).startOf('day');

  // In test mode, use calendar days
  if (isTestMode()) {
    return end.diff(start, 'day') + 1;
  }

  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };

  let businessDays = 0;
  let current = start;

  // Count each day from start to end (inclusive)
  while (current.isBefore(end) || current.isSame(end, 'day')) {
    const dayOfWeek = current.day(); // 0 = Sunday, 6 = Saturday
    const dateStr = current.format('YYYY-MM-DD');

    // For express priority: count all days (including weekends) but exclude holidays
    // For standard priority: count only working days (Mon-Fri) and exclude holidays
    const isWorkingDay = priority === 'express'
      ? true  // Express includes weekends
      : (dayOfWeek >= config.startDay && dayOfWeek <= config.endDay);

    const isNotHoliday = !holidaysCache.has(dateStr);

    if (isWorkingDay && isNotHoliday) {
      businessDays++;
    }

    current = current.add(1, 'day');

    // Safety check to prevent infinite loops
    if (current.diff(start, 'day') > 730) { // 2 years
      console.error('[TAT] Safety break - exceeded 2 years in business days calculation');
      break;
    }
  }

  return businessDays;
}

