import Availability from './availability';
import AvailabilityException from './availability-exception';
import { toDate, ExceptionDate } from './exception-date';
import Item from './item';

const MINUTES_IN_A_DAY = 1440;

export function isItemAvailableNow(item: Item) {
  return isItemAvailable(item, new Date());
}

export function isItemAvailable(item: Item, date: Date) {
  const availability = (item?.condition?.conditions ?? [])[3]?.availability;

  if (!availability) {
    return true;
  }

  return isAvailable(availability, date);
}

export function isAvailableNow(availability: Availability) {
  return isAvailable(availability, new Date());
}

export function isAvailable(availability: Availability, date: Date) {
  const exceptionAvailability = _isAvailableInExceptions(availability, date);

  if (exceptionAvailability === 'available') {
    return true;
  } else if (exceptionAvailability === 'unavailable') {
    return false;
  }

  return _isRegularlyAvailable(availability, date);
}

function _isRegularlyAvailable(availability: Availability, date: Date) {
  const weekMinute =
    date.getDay() * MINUTES_IN_A_DAY + date.getHours() * 60 + date.getMinutes();

  for (const segment of availability.weekly) {
    if (
      weekMinute >= segment.minuteOfWeek &&
      segment.minuteOfWeek + segment.durationMins >= weekMinute
    ) {
      return true;
    }
  }

  return !availability.weekly.length;
}

function _isAvailableInExceptions(availability: Availability, date: Date) {
  if (!availability.exceptions) {
    return 'not-mentioned';
  }

  for (const exception of availability.exceptions) {
    if (_isDateInsideException(exception, date)) {
      return exception.available ? 'available' : 'unavailable';
    }
  }

  return 'not-mentioned';
}

function _isDateInsideException(exception: AvailabilityException, date: Date) {
  const start = toDate(exception.start);
  const end = toDate(exception.end);

  return date > start && date < end;
}

export { Item, Availability, AvailabilityException, ExceptionDate };
