import { dt } from "@/lib/dt"
import {
  getHotel,
  getPackages,
  getRoomsAvailability,
} from "@/lib/trpc/memoizedRequests"

import { auth } from "@/auth"
import { generateChildrenString } from "@/components/HotelReservation/utils"
import RatesProvider from "@/providers/RatesProvider"
import { isValidSession } from "@/utils/session"

import { combineRoomAvailabilities } from "../utils"
import RateSummary from "./RateSummary"
import Rooms from "./Rooms"

import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { RoomsContainerProps } from "@/types/components/hotelReservation/selectRate/roomsContainer"
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { Lang } from "@/constants/languages"

export function preload(
  hotelId: string,
  lang: Lang,
  fromDate: string,
  toDate: string,
  adults: number[],
  children?: Child[]
) {
  void getHotel({ hotelId, isCardOnlyPayment: false, language: lang })
  void getPackages({
    adults: adults[0],
    children: children ? children?.length : undefined,
    endDate: toDate,
    hotelId,
    packageCodes: [
      RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
      RoomPackageCodeEnum.PET_ROOM,
      RoomPackageCodeEnum.ALLERGY_ROOM,
    ],
    startDate: fromDate,
  })

  const uniqueAdultsCount = Array.from(new Set(adults))
  uniqueAdultsCount.forEach((adultsInRoom) => {
    void getRoomsAvailability({
      adults: adultsInRoom,
      children: children ? generateChildrenString(children) : undefined,
      hotelId: +hotelId,
      roomStayEndDate: toDate,
      roomStayStartDate: fromDate,
    })
  })
}

export async function RoomsContainer({
  adultArray,
  booking,
  childArray,
  fromDate,
  hotelId,
  lang,
  toDate,
}: RoomsContainerProps) {
  const session = await auth()
  const isUserLoggedIn = isValidSession(session)

  const fromDateString = dt(fromDate).format("YYYY-MM-DD")
  const toDateString = dt(toDate).format("YYYY-MM-DD")

  const hotelData = await getHotel({
    hotelId: hotelId.toString(),
    isCardOnlyPayment: false,
    language: lang,
  })

  const uniqueAdultsCount = Array.from(new Set(adultArray))
  const roomsAvailabilityResults = await Promise.allSettled(
    uniqueAdultsCount.map((adultCount) =>
      getRoomsAvailability({
        adults: adultCount,
        hotelId: hotelId,
        roomStayEndDate: toDateString,
        roomStayStartDate: fromDateString,
        children:
          childArray && childArray.length > 0
            ? generateChildrenString(childArray)
            : undefined,
      })
    )
  )

  const roomsAvailability = combineRoomAvailabilities(roomsAvailabilityResults)

  const packages = await getPackages({
    adults: adultArray[0],
    children: childArray ? childArray.length : undefined,
    endDate: toDateString,
    hotelId: hotelId.toString(),
    packageCodes: [
      RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
      RoomPackageCodeEnum.PET_ROOM,
      RoomPackageCodeEnum.ALLERGY_ROOM,
    ],
    startDate: fromDateString,
  })

  if (!hotelData?.hotel) {
    return null
  }

  if (packages === null) {
    // TODO: Log packages error
    console.error("[RoomsContainer] unable to fetch packages")
  }

  return (
    <RatesProvider
      booking={booking}
      hotelType={hotelData.hotel.hotelType}
      isUserLoggedIn={isUserLoggedIn}
      packages={packages}
      roomCategories={hotelData.roomCategories}
      roomsAvailability={roomsAvailability}
      vat={hotelData.hotel.vat}
    >
      <Rooms />
      <RateSummary isUserLoggedIn={isUserLoggedIn} />
    </RatesProvider>
  )
}
