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

import { safeTry } from "@scandic-hotels/common/utils/safeTry"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"

import { env } from "../../env/server"
import { BookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import { MapContainer } from "../components/MapContainer"
import {
  getFiltersFromHotels,
  getHotels,
} from "../components/SelectHotel/helpers"
import {
  SelectHotelMap,
  SelectHotelMapSkeleton,
} from "../components/SelectHotel/SelectHotelMap"
import { getHotelSearchDetails } from "../misc/getHotelSearchDetails"
import { getSelectHotelTracking } from "../misc/selectHotelTracking"
import { getCityCoordinates } from "../trpc/memoizedRequests/getCityCoordinates"
import { parseSelectHotelSearchParams } from "../utils/url"

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

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

export async function SelectHotelMapPage({
  lang,
  searchParams,
  config,
}: {
  lang: Lang
  searchParams: NextSearchParams
  config: BookingFlowConfig
}) {
  const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID
  const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY

  const booking = parseSelectHotelSearchParams(searchParams)

  if (!booking) return notFound()

  const getHotelSearchDetailsPromise = safeTry(
    getHotelSearchDetails({ ...booking, lang })
  )

  const [searchDetails] = await getHotelSearchDetailsPromise

  if (!searchDetails) {
    return notFound()
  }

  const {
    city,
    cityIdentifier,
    hotel: isAlternativeFor,
    redemption,
  } = searchDetails

  if (!city) {
    return notFound()
  }

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

  const cityCoordinates = await getCityCoordinates({
    city: city.name,
    hotel: { address: hotels?.[0]?.hotel?.address.streetAddress },
  })

  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 = booking.bookingCode
    ? hotels?.some((hotel) => hotel.availability.bookingCode)
    : false

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

  const filterList = getFiltersFromHotels(hotels, isBookingCodeRateAvailable)

  const suspenseKey = stringify(searchParams)

  return (
    <BookingFlowConfig config={config}>
      <MapContainer>
        <Suspense key={suspenseKey} fallback={<SelectHotelMapSkeleton />}>
          <SelectHotelMap
            apiKey={googleMapsApiKey}
            mapId={googleMapId}
            hotels={hotels}
            cityCoordinates={cityCoordinates}
            bookingCode={booking.bookingCode}
            isBookingCodeRateAvailable={isBookingCodeRateAvailable}
            filterList={filterList}
          />
          <TrackingSDK
            hotelInfo={hotelsTrackingData}
            pageData={pageTrackingData}
          />
        </Suspense>
      </MapContainer>
    </BookingFlowConfig>
  )
}
