/**
 * SLA Tracker Utility
 * Handles real-time SLA tracking with working hours (excludes weekends, non-working hours, holidays)
 * Configuration is fetched from backend via configService
 */

import { configService } from '@/services/configService';

// Default working hours (fallback if config not loaded)
let WORK_START_HOUR = 9;
let WORK_END_HOUR = 18;
let WORK_START_DAY = 1;
let WORK_END_DAY = 5;
let configLoaded = false;

// Lazy initialization of configuration
async function ensureConfigLoaded() {
  if (configLoaded) return;

  try {
    const config = await configService.getConfig();
    WORK_START_HOUR = config.workingHours.START_HOUR;
    WORK_END_HOUR = config.workingHours.END_HOUR;
    WORK_START_DAY = config.workingHours.START_DAY;
    WORK_END_DAY = config.workingHours.END_DAY;
    configLoaded = true;
  } catch (error) {
    console.warn('[SLA Tracker] ⚠️ Using default working hours (9 AM - 6 PM)');
  }
}

// Initialize config on first import (non-blocking)
ensureConfigLoaded().catch(() => { });

/**
 * Check if current time is within working hours
 * @param date - Date to check
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function isWorkingTime(date: Date = new Date(), priority: string = 'standard'): boolean {
  const day = date.getDay(); // 0 = Sunday, 6 = Saturday
  const hour = date.getHours();

  // For standard priority: exclude weekends
  // For express priority: include weekends (calendar days)
  if (priority === 'standard') {
    if (day < WORK_START_DAY || day > WORK_END_DAY) {
      return false;
    }
  }

  // Working hours check (applies to both priorities)
  if (hour < WORK_START_HOUR || hour >= WORK_END_HOUR) {
    return false;
  }


  return true;
}

/**
 * Get next working time from a given date
 * @param date - Current date
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function getNextWorkingTime(date: Date = new Date(), priority: string = 'standard'): Date {
  const result = new Date(date);

  // If already in working time, return as is
  if (isWorkingTime(result, priority)) {
    return result;
  }

  // For standard priority: skip weekends
  if (priority === 'standard') {
    const day = result.getDay();
    if (day === 0) { // Sunday
      result.setDate(result.getDate() + 1);
      result.setHours(WORK_START_HOUR, 0, 0, 0);
      return result;
    }
    if (day === 6) { // Saturday
      result.setDate(result.getDate() + 2);
      result.setHours(WORK_START_HOUR, 0, 0, 0);
      return result;
    }
  }

  // If before work hours, move to work start
  if (result.getHours() < WORK_START_HOUR) {
    result.setHours(WORK_START_HOUR, 0, 0, 0);
    return result;
  }

  // If after work hours, move to next day work start
  if (result.getHours() >= WORK_END_HOUR) {
    result.setDate(result.getDate() + 1);
    result.setHours(WORK_START_HOUR, 0, 0, 0);
    // Check if next day is weekend (only for standard priority)
    return getNextWorkingTime(result, priority);
  }

  return result;
}

/**
 * Calculate elapsed working hours between two dates with minute precision
 * @param startDate - Start date
 * @param endDate - End date (defaults to now)
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function calculateElapsedWorkingHours(startDate: Date, endDate: Date = new Date(), priority: string = 'standard'): number {
  let current = new Date(startDate);
  const end = new Date(endDate);
  let elapsedMinutes = 0;

  // Move minute by minute and count only working minutes
  while (current < end) {
    if (isWorkingTime(current, priority)) {
      elapsedMinutes++;
    }
    current.setMinutes(current.getMinutes() + 1);

    // Safety: stop if calculating more than 1 year
    const hoursSoFar = elapsedMinutes / 60;
    if (hoursSoFar > 8760) break;
  }

  // Convert minutes to hours (with decimal precision)
  return elapsedMinutes / 60;
}

/**
 * Calculate remaining working hours to deadline
 * @param deadline - Deadline date
 * @param fromDate - Start date (defaults to now)
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function calculateRemainingWorkingHours(deadline: Date, fromDate: Date = new Date(), priority: string = 'standard'): number {
  const deadlineTime = new Date(deadline).getTime();
  const currentTime = new Date(fromDate).getTime();

  // If deadline has passed
  if (deadlineTime <= currentTime) {
    return 0;
  }

  // Calculate remaining working hours
  return calculateElapsedWorkingHours(fromDate, deadline, priority);
}

/**
 * Calculate SLA progress percentage
 * @param startDate - Start date
 * @param deadline - Deadline date
 * @param currentDate - Current date (defaults to now)
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function calculateSLAProgress(startDate: Date, deadline: Date, currentDate: Date = new Date(), priority: string = 'standard'): number {
  const totalHours = calculateElapsedWorkingHours(startDate, deadline, priority);
  const elapsedHours = calculateElapsedWorkingHours(startDate, currentDate, priority);

  if (totalHours === 0) return 0;

  const progress = (elapsedHours / totalHours) * 100;
  return Math.min(Math.max(progress, 0), 100); // Clamp between 0 and 100
}

/**
 * Get SLA status information
 */
export interface SLAStatus {
  isWorkingTime: boolean;
  progress: number;
  elapsedHours: number;
  remainingHours: number;
  totalHours: number;
  isPaused: boolean;
  nextWorkingTime?: Date;
  statusText: string;
}

export function getSLAStatus(startDate: string | Date, deadline: string | Date, priority: string = 'standard'): SLAStatus {
  const start = new Date(startDate);
  const end = new Date(deadline);
  const now = new Date();

  const isWorking = isWorkingTime(now, priority);
  const elapsedHours = calculateElapsedWorkingHours(start, now, priority);
  const totalHours = calculateElapsedWorkingHours(start, end, priority);
  const remainingHours = Math.max(0, totalHours - elapsedHours);
  const progress = calculateSLAProgress(start, end, now, priority);

  let statusText = '';
  if (!isWorking) {
    statusText = priority === 'express'
      ? 'SLA tracking paused (outside working hours)'
      : 'SLA tracking paused (outside working hours/days)';
  } else if (remainingHours === 0) {
    statusText = 'SLA deadline reached';
  } else if (progress >= 100) {
    statusText = 'SLA breached';
  } else if (progress >= 75) {
    statusText = 'SLA critical';
  } else if (progress >= 50) {
    statusText = 'SLA warning';
  } else {
    statusText = 'On track';
  }

  return {
    isWorkingTime: isWorking,
    progress,
    elapsedHours,
    remainingHours,
    totalHours,
    isPaused: !isWorking,
    nextWorkingTime: !isWorking ? getNextWorkingTime(now, priority) : undefined,
    statusText
  };
}

/**
 * Format decimal hours to hours and minutes format
 * Considers 8 working hours = 1 day (consistent with TAT calculations and backend formatTime)
 * Uses "hour" (singular) for 1 hour, "hours" (plural) for multiple hours
 * Matches backend formatTime format from tatTimeUtils.ts for consistency
 * Examples: 1 -> "1 hour", 8 -> "1 day", 9 -> "1 day 1 hour", 16 -> "2 days"
 */
export function formatHoursMinutes(hours: number | null | undefined): string {
  if (hours === null || hours === undefined || hours < 0) return '0 hours';
  if (hours === 0) return '0 hours';

  const WORKING_HOURS_PER_DAY = 8;

  // If less than 1 hour, show minutes only
  if (hours < 1) {
    const m = Math.round(hours * 60);
    return m > 0 ? `${m}m` : '0 hours';
  }

  // Calculate days and remaining hours (8 hours = 1 day)
  // Match backend formatTime logic from Re_Backend/src/utils/tatTimeUtils.ts
  const days = Math.floor(hours / WORKING_HOURS_PER_DAY);
  const remainingHrs = Math.floor(hours % WORKING_HOURS_PER_DAY);
  const minutes = Math.round((hours % 1) * 60);

  // If we have days, format with days (matching backend format)
  if (days > 0) {
    const dayLabel = days === 1 ? 'day' : 'days';
    const hourLabel = remainingHrs === 1 ? 'hour' : 'hours';
    const minuteLabel = minutes === 1 ? 'min' : 'm';

    if (minutes > 0) {
      return `${days} ${dayLabel} ${remainingHrs} ${hourLabel} ${minutes}${minuteLabel}`;
    } else {
      return `${days} ${dayLabel} ${remainingHrs} ${hourLabel}`;
    }
  }

  // No days, just hours and minutes
  const hourLabel = remainingHrs === 1 ? 'hour' : 'hours';
  const minuteLabel = minutes === 1 ? 'min' : 'm';

  if (minutes > 0) {
    return `${remainingHrs} ${hourLabel} ${minutes}${minuteLabel}`;
  } else {
    return `${remainingHrs} ${hourLabel}`;
  }
}

/**
 * Format working hours for display
 */
export function formatWorkingHours(hours: number): string {
  if (hours === 0) return '0h';
  if (hours < 0) return '0h';

  const totalMinutes = Math.round(hours * 60);
  const days = Math.floor(totalMinutes / (8 * 60)); // 8 working hours per day
  const remainingMinutes = totalMinutes % (8 * 60);
  const remainingHours = Math.floor(remainingMinutes / 60);
  const minutes = remainingMinutes % 60;

  if (days > 0 && remainingHours > 0 && minutes > 0) {
    return `${days}d ${remainingHours}h ${minutes}m`;
  } else if (days > 0 && remainingHours > 0) {
    return `${days}d ${remainingHours}h`;
  } else if (days > 0) {
    return `${days}d`;
  } else if (remainingHours > 0 && minutes > 0) {
    return `${remainingHours}h ${minutes}m`;
  } else if (remainingHours > 0) {
    return `${remainingHours}h`;
  } else {
    return `${minutes}m`;
  }
}

/**
 * Get time until next working period
 * @param priority - Priority type ('express' includes weekends, 'standard' excludes weekends)
 */
export function getTimeUntilNextWorking(priority: string = 'standard'): string {
  if (isWorkingTime(new Date(), priority)) {
    return 'In working hours';
  }

  const now = new Date();
  const next = getNextWorkingTime(now, priority);
  const diff = next.getTime() - now.getTime();

  const hours = Math.floor(diff / (1000 * 60 * 60));
  const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));

  if (hours > 24) {
    const days = Math.floor(hours / 24);
    return `Resumes in ${days}d ${hours % 24}h`;
  } else if (hours > 0) {
    return `Resumes in ${hours}h ${minutes}m`;
  } else {
    return `Resumes in ${minutes}m`;
  }
}
