import { SortOrder } from "@/types/components/hotelReservation/selectHotel/hotelSorter"
import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/helpers"

function getPricePerNight(hotel: HotelResponse): number {
  return (
    hotel.availability.productType?.member?.localPrice?.pricePerNight ??
    hotel.availability.productType?.public?.localPrice?.pricePerNight ??
    hotel.availability.productType?.redemptions?.find(
      (r) => r?.localPrice.pointsPerStay
    )?.localPrice?.pointsPerStay ??
    Infinity
  )
}

export function getSortedHotels({
  hotels,
  sortBy,
  bookingCode,
}: {
  hotels: HotelResponse[]
  sortBy: string
  bookingCode: string | null
}) {
  const availableHotels = hotels.filter(
    (hotel) => !!hotel.availability.productType
  )
  const unavailableHotels = hotels.filter(
    (hotel) => !hotel.availability.productType
  )

  const sortingStrategies: Record<
    string,
    (a: HotelResponse, b: HotelResponse) => number
  > = {
    [SortOrder.Name]: (a: HotelResponse, b: HotelResponse) =>
      a.hotel.name.localeCompare(b.hotel.name),
    [SortOrder.TripAdvisorRating]: (a: HotelResponse, b: HotelResponse) =>
      (b.hotel.ratings?.tripAdvisor.rating ?? 0) -
      (a.hotel.ratings?.tripAdvisor.rating ?? 0),
    [SortOrder.Price]: (a: HotelResponse, b: HotelResponse) =>
      getPricePerNight(a) - getPricePerNight(b),
    [SortOrder.Distance]: (a: HotelResponse, b: HotelResponse) =>
      a.hotel.location.distanceToCentre - b.hotel.location.distanceToCentre,
  }

  const sortStrategy =
    sortingStrategies[sortBy] ?? sortingStrategies[SortOrder.Distance]

  if (bookingCode) {
    const bookingCodeRateHotels = availableHotels.filter(
      (hotel) => hotel.availability.bookingCode
    )
    const regularRateHotels = availableHotels.filter(
      (hotel) => !hotel.availability.bookingCode
    )

    return bookingCodeRateHotels
      .sort(sortStrategy)
      .concat(regularRateHotels.sort(sortStrategy))
      .concat(unavailableHotels.sort(sortStrategy))
  }

  return availableHotels
    .sort(sortStrategy)
    .concat(unavailableHotels.sort(sortStrategy))
}
