import { Availability, AvailabilityType } from '../models';

/**
 * Valid availability status codes for downloads.
 *
 * These codes indicate that a digital product can be downloaded:
 * - 2: Immediately available for download
 * - 32: Available with lead time (minor delay)
 * - 256: Pre-order available (future availability)
 * - 1024: Backorder available (temporary out of stock)
 * - 2048: Special order available (requires special handling)
 * - 4096: Digital delivery available (standard digital product)
 *
 * Note: These codes are defined by the availability API service.
 */
const VALID_DOWNLOAD_STATUS_CODES: AvailabilityType[] = [
  AvailabilityType.PrebookAtBuyer,
  AvailabilityType.PrebookAtRetailer,
  AvailabilityType.PrebookAtSupplier,
  AvailabilityType.Available,
  AvailabilityType.OnDemand,
  AvailabilityType.AtProductionDate,
];

/**
 * Validates if a download item is available.
 *
 * Business rules:
 * - Supplier ID 16 with 0 stock = unavailable
 * - Must have valid availability type code (see VALID_DOWNLOAD_STATUS_CODES)
 *
 * @param availability The availability DTO to validate
 * @returns true if download is available, false otherwise
 */
export function isDownloadAvailable(
  availability: Availability | null | undefined,
): boolean {
  if (!availability) return false;

  // Supplier 16 with 0 in stock is not available
  if (availability.supplierId === 16 && availability.qty === 0) {
    return false;
  }

  // Check if status code is valid for downloads
  return VALID_DOWNLOAD_STATUS_CODES.includes(availability.status);
}

/**
 * Selects the preferred availability from a list of availabilities.
 *
 * The preferred availability is marked with `preferred === 1` by the API.
 *
 * @param availabilities List of availability DTOs
 * @returns The preferred availability, or undefined if none found
 */
export function selectPreferredAvailability(
  availabilities: Availability[],
): Availability | undefined {
  return availabilities.find((av) => av.preferred === 1);
}

/**
 * Calculates the estimated shipping/delivery date based on API response.
 *
 * Business rule:
 * - If requestStatusCode === '32', use altAt (alternative date)
 * - Otherwise, use at (standard date)
 *
 * @param availability The availability DTO
 * @returns The estimated date string, or undefined
 */
export function calculateEstimatedDate(
  availability: Availability | null | undefined,
): string | undefined {
  if (!availability) return undefined;

  return availability.requestStatusCode === '32'
    ? availability.altAt
    : availability.at;
}

/**
 * Type guard to check if an availability has a valid price.
 *
 * @param availability The availability DTO
 * @returns true if availability has a price with a value
 */
export function hasValidPrice(
  availability: Availability | null | undefined,
): availability is Availability & {
  price: NonNullable<Availability['price']>;
} {
  return !!(
    availability?.price?.value?.value && availability.price.value.value > 0
  );
}

/**
 * Checks if an availability is price-maintained.
 *
 * @param availability The availability DTO
 * @returns true if price-maintained flag is set
 */
export function isPriceMaintained(
  availability: Availability | null | undefined,
): boolean {
  return availability?.priceMaintained === true;
}
