import type { WeekdayAvailability } from "@capakraken/shared";

export interface ChargeabilityAllocation {
  startDate: Date;
  endDate: Date;
  hoursPerDay: number;
}

export interface ChargeabilityResult {
  availableHours: number;
  bookedHours: number;
  chargeability: number; // 0-100, rounded
}

// Maps JS getDay() (0=Sun..6=Sat) to WeekdayAvailability keys
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
  "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday",
];

/** Count working hours a resource has available in [start, end] based on their schedule. */
export function computeAvailableHours(
  availability: WeekdayAvailability,
  start: Date,
  end: Date,
): number {
  let hours = 0;
  const cur = new Date(start);
  cur.setHours(0, 0, 0, 0);
  const endNorm = new Date(end);
  endNorm.setHours(0, 0, 0, 0);
  while (cur <= endNorm) {
    const key = DAY_KEYS[cur.getDay()];
    hours += key ? (availability[key] ?? 0) : 0;
    cur.setDate(cur.getDate() + 1);
  }
  return hours;
}

/** Count booked hours from allocations overlapping [start, end], working days only. */
export function computeBookedHours(
  availability: WeekdayAvailability,
  allocations: ChargeabilityAllocation[],
  start: Date,
  end: Date,
): number {
  let hours = 0;
  const startNorm = new Date(start); startNorm.setHours(0, 0, 0, 0);
  const endNorm   = new Date(end);   endNorm.setHours(0, 0, 0, 0);
  for (const alloc of allocations) {
    const aStart = new Date(alloc.startDate); aStart.setHours(0, 0, 0, 0);
    const aEnd   = new Date(alloc.endDate);   aEnd.setHours(0, 0, 0, 0);
    const overlapStart = aStart > startNorm ? aStart : startNorm;
    const overlapEnd   = aEnd   < endNorm   ? aEnd   : endNorm;
    if (overlapStart > overlapEnd) continue;
    const cur = new Date(overlapStart);
    while (cur <= overlapEnd) {
      const key = DAY_KEYS[cur.getDay()];
      if (key && (availability[key] ?? 0) > 0) {
        hours += alloc.hoursPerDay;
      }
      cur.setDate(cur.getDate() + 1);
    }
  }
  return hours;
}

/** Compute chargeability metrics for a resource over a date range. */
export function computeChargeability(
  availability: WeekdayAvailability,
  allocations: ChargeabilityAllocation[],
  start: Date,
  end: Date,
): ChargeabilityResult {
  const availableHours = computeAvailableHours(availability, start, end);
  const bookedHours    = computeBookedHours(availability, allocations, start, end);
  const chargeability  = availableHours > 0
    ? Math.min(100, Math.round((bookedHours / availableHours) * 100))
    : 0;
  return { availableHours, bookedHours, chargeability };
}
