import { notFound } from "next/navigation"

import { REDEMPTION } from "@/constants/booking"
import { getLocations } from "@/lib/trpc/memoizedRequests"

import { generateChildrenString } from "@/components/HotelReservation/utils"
import { safeTry } from "@/utils/safeTry"

import type { BookingSearchType } from "@/types/components/hotelReservation/booking"
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
import {
  type HotelLocation,
  isHotelLocation,
  type Location,
} from "@/types/trpc/routers/hotel/locations"

export type ChildrenInRoom = (Child[] | null)[] | null
export type ChildrenInRoomString = (string | null)[] | null

interface HotelSearchDetails {
  adultsInRoom: number[]
  bookingCode?: string
  childrenInRoom: ChildrenInRoom
  childrenInRoomString: ChildrenInRoomString
  city: Location | null
  cityName: string | undefined
  hotel: HotelLocation | null
  noOfRooms: number
  redemption?: boolean
}

export async function getHotelSearchDetails(
  params: {
    hotelId?: string
    city?: string
    rooms?: {
      adults: number
      childrenInRoom?: Child[]
    }[]
    bookingCode?: string
    searchType?: BookingSearchType
  },
  isAlternativeHotels?: boolean
): Promise<HotelSearchDetails | null> {
  const [locations, error] = await safeTry(getLocations())
  if (!locations || error) {
    return null
  }

  const hotel = params.hotelId
    ? ((locations.find(
        (location) =>
          isHotelLocation(location) &&
          "operaId" in location &&
          location.operaId === params.hotelId
      ) as HotelLocation | undefined) ?? null)
    : null

  if (isAlternativeHotels && !hotel) {
    return notFound()
  }

  const cityName = isAlternativeHotels
    ? hotel?.relationships.city.name
    : params.city

  const city = cityName
    ? (locations.find(
        (location) =>
          "cityIdentifier" in location &&
          location.cityIdentifier?.toLowerCase() === cityName.toLowerCase()
      ) ?? null)
    : null

  if (!city && !hotel) return notFound()
  if (isAlternativeHotels && (!city || !hotel)) return notFound()

  let adultsInRoom: number[] = []
  let childrenInRoom: ChildrenInRoom = null
  let childrenInRoomString: ChildrenInRoomString = null

  const { rooms } = params

  if (rooms?.length) {
    adultsInRoom = rooms.map((room) => room.adults ?? 0)

    childrenInRoom = rooms.map((room) => room.childrenInRoom ?? null)
    childrenInRoomString = rooms.map((room) =>
      room.childrenInRoom ? generateChildrenString(room.childrenInRoom) : null
    )
  }

  return {
    adultsInRoom,
    bookingCode: params.bookingCode ?? undefined,
    childrenInRoom,
    childrenInRoomString,
    city,
    cityName,
    hotel,
    noOfRooms: rooms?.length ?? 0,
    redemption: params.searchType === REDEMPTION,
  }
}
