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 "@scandic-hotels/common/constants/familyAndFriends"
import { NoAvailabilityTracking } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"

import FnFNotAllowedAlert from "../components/FnFNotAllowedAlert"
import { SelectHotel } from "../components/SelectHotel"
import { getHotels } from "../components/SelectHotel/helpers"
import { getHotelSearchDetails } from "../misc/getHotelSearchDetails"
import { getSelectHotelTracking } from "../misc/selectHotelTracking"
import { parseSelectHotelSearchParams } from "../utils/url"

import type { Lang } from "@scandic-hotels/common/constants/language"

import type { NextSearchParams } from "../types"

export { SelectHotelSkeleton as SelectHotelPageSkeleton } from "../components/SelectHotel"

export async function SelectHotelPage({
  lang,
  searchParams,
}: {
  lang: Lang
  searchParams: NextSearchParams
}) {
  const booking = parseSelectHotelSearchParams(searchParams)

  if (!booking) return notFound()

  const searchDetails = await getHotelSearchDetails({ ...booking, lang })

  if (!searchDetails || !searchDetails.city) return notFound()

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

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

  const { city, redemption } = searchDetails

  const hotels = await getHotels({
    fromDate: booking.fromDate,
    toDate: booking.toDate,
    rooms: booking.rooms,
    isAlternativeFor: null,
    bookingCode: booking.bookingCode,
    city: city,
    redemption: !!redemption,
    lang,
  })

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

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

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

  const { hotelsTrackingData, pageTrackingData } = getSelectHotelTracking({
    rooms: booking.rooms,
    lang: lang,
    pageId: "select-hotel",
    pageName: "hotelreservation|select-hotel",
    siteSections: "hotelreservation|select-hotel",
    arrivalDate,
    departureDate,
    hotelsResult: hotels?.length ?? 0,
    searchTerm: city.name,
    country: hotels?.[0]?.hotel.address.country,
    hotelCity: hotels?.[0]?.hotel.address.city,
    bookingCode: booking.bookingCode,
    isBookingCodeRateAvailable,
    isRedemption: redemption,
    isRedemptionAvailable: isRedemptionAvailability,
  })

  const suspenseKey = stringify(searchParams)

  const shouldTrackNoAvailability = !!(
    hotels.every((hotel) => hotel.availability.status !== "Available") ||
    (booking.bookingCode && hotels.length > 0 && !isBookingCodeRateAvailable)
  )

  return (
    <>
      <SelectHotel
        bookingCode={booking.bookingCode}
        isBookingCodeRateAvailable={isBookingCodeRateAvailable}
        city={city}
        hotels={hotels}
        title={city.name}
        lang={lang}
      />
      <Suspense key={`${suspenseKey}-tracking`} fallback={null}>
        <TrackingSDK
          hotelInfo={hotelsTrackingData}
          pageData={pageTrackingData}
        />
        <NoAvailabilityTracking
          lang={lang}
          hotelsTrackingData={hotelsTrackingData}
          pageTrackingData={pageTrackingData}
          shouldTrackNoAvailability={shouldTrackNoAvailability}
        />
      </Suspense>
    </>
  )
}
