import stringify from "json-stable-stringify-without-jsonify"
import { cookies } from "next/headers"
import { notFound } from "next/navigation"
import { Suspense } from "react"

import { FamilyAndFriendsCodes } from "@/constants/booking"
import { alternativeHotelsMap } from "@/constants/routes/hotelReservation"

import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert"
import SelectHotel from "@/components/HotelReservation/SelectHotel"
import { getHotels } from "@/components/HotelReservation/SelectHotel/helpers"
import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
import { getHotelSearchDetails } from "@/utils/hotelSearchDetails"
import { parseSelectHotelSearchParams } from "@/utils/url"

import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"

export default async function AlternativeHotelsPage(
  props: PageArgs<LangParams, NextSearchParams>
) {
  const searchParams = await props.searchParams
  const params = await props.params

  const booking = parseSelectHotelSearchParams(searchParams)

  if (!booking) return notFound()

  const searchDetails = await getHotelSearchDetails(booking, true)

  if (!searchDetails || !searchDetails.hotel || !searchDetails.city) {
    return notFound()
  }

  const {
    adultsInRoom,
    bookingCode,
    childrenInRoom,
    city,
    cityName,
    hotel: isAlternativeFor,
    noOfRooms,
    redemption,
  } = searchDetails

  if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) {
    const cookieStore = await cookies()
    const isInvalidFNF = cookieStore.get("sc")?.value !== "1"

    if (isInvalidFNF) {
      return <FnFNotAllowedAlert />
    }
  }

  // TODO: This needs to be refactored into its
  // own functions
  const hotels = await getHotels({
    fromDate: booking.fromDate,
    toDate: booking.toDate,
    rooms: booking.rooms,
    isAlternativeFor,
    bookingCode,
    city,
    redemption: !!redemption,
  })

  const arrivalDate = new Date(booking.fromDate)
  const departureDate = new Date(booking.toDate)

  const isRedemptionAvailability = redemption
    ? hotels.some(
        (hotel) => hotel.availability.productType?.redemptions?.length
      )
    : false

  const isBookingCodeRateAvailable = bookingCode
    ? hotels.some(
        (hotel) =>
          hotel.availability.bookingCode &&
          hotel.availability.status === "Available"
      )
    : false

  const { hotelsTrackingData, pageTrackingData } = getTracking(
    params.lang,
    !!isAlternativeFor,
    arrivalDate,
    departureDate,
    adultsInRoom,
    childrenInRoom,
    hotels?.length ?? 0,
    booking.hotelId,
    noOfRooms,
    hotels?.[0]?.hotel.address.country,
    hotels?.[0]?.hotel.address.city,
    cityName,
    bookingCode,
    isBookingCodeRateAvailable,
    redemption,
    isRedemptionAvailability
  )

  const mapHref = alternativeHotelsMap(params.lang)

  const intl = await getIntl()
  const title = intl.formatMessage(
    {
      defaultMessage: "Alternatives for {value}",
    },
    {
      value: isAlternativeFor.name,
    }
  )
  const suspenseKey = stringify(searchParams)
  return (
    <>
      <SelectHotel
        bookingCode={bookingCode}
        city={city}
        hotels={hotels}
        isAlternative={!!isAlternativeFor}
        mapHref={mapHref}
        title={title}
      />
      <Suspense key={`${suspenseKey}-tracking`} fallback={null}>
        <TrackingSDK
          pageData={pageTrackingData}
          hotelInfo={hotelsTrackingData}
        />
      </Suspense>
    </>
  )
}
