import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { Suspense } from "react"

import { env } from "@/env/server"
import { getCityCoordinates } from "@/lib/trpc/memoizedRequests"

import {
  fetchAvailableHotels,
  getFiltersFromHotels,
} from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import { safeTry } from "@/utils/safeTry"

import { getHotelPins } from "../../HotelCardDialogListing/utils"
import SelectHotelMap from "."

import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import type {
  HotelData,
  NullableHotelData,
} from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelMapContainerProps } from "@/types/components/hotelReservation/selectHotel/map"
import {
  TrackingChannelEnum,
  type TrackingSDKHotelInfo,
  type TrackingSDKPageData,
} from "@/types/components/tracking"

function isValidHotelData(hotel: NullableHotelData): hotel is HotelData {
  return hotel !== null && hotel !== undefined
}

export async function SelectHotelMapContainer({
  city,
  selectHotelParams,
  adultsInRoom,
  childrenInRoom,
  childrenInRoomString,
}: SelectHotelMapContainerProps) {
  const lang = getLang()
  const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID
  const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY

  const fetchAvailableHotelsPromise = safeTry(
    fetchAvailableHotels({
      cityId: city.id,
      roomStayStartDate: selectHotelParams.fromDate,
      roomStayEndDate: selectHotelParams.toDate,
      adults: adultsInRoom,
      children: childrenInRoomString,
    })
  )

  const [hotels] = await fetchAvailableHotelsPromise

  const validHotels = hotels?.filter(isValidHotelData) || []

  const hotelPins = getHotelPins(validHotels)
  const filterList = getFiltersFromHotels(validHotels)
  const cityCoordinates = await getCityCoordinates({
    city: city.name,
    hotel: { address: hotels?.[0]?.hotelData?.address.streetAddress },
  })

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

  const pageTrackingData: TrackingSDKPageData = {
    pageId: "select-hotel",
    domainLanguage: lang,
    channel: TrackingChannelEnum["hotelreservation"],
    pageName: "hotelreservation|select-hotel|mapview",
    siteSections: "hotelreservation|select-hotel|mapview",
    pageType: "bookinghotelsmapviewpage",
    siteVersion: "new-web",
  }

  const hotelsTrackingData: TrackingSDKHotelInfo = {
    availableResults: validHotels.length,
    searchTerm: selectHotelParams.city,
    arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
    departureDate: format(departureDate, "yyyy-MM-dd"),
    noOfAdults: adultsInRoom,
    noOfChildren: childrenInRoom?.length,
    ageOfChildren: childrenInRoom?.map((c) => c.age).join(","),
    childBedPreference: childrenInRoom
      ?.map((c) => ChildBedMapEnum[c.bed])
      .join("|"),
    noOfRooms: 1, // // TODO: Handle multiple rooms
    duration: differenceInCalendarDays(departureDate, arrivalDate),
    leadTime: differenceInCalendarDays(arrivalDate, new Date()),
    searchType: "destination",
    bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
    country: validHotels?.[0]?.hotelData.address.country,
    region: validHotels?.[0]?.hotelData.address.city,
  }

  return (
    <>
      <SelectHotelMap
        apiKey={googleMapsApiKey}
        hotelPins={hotelPins}
        mapId={googleMapId}
        hotels={validHotels}
        filterList={filterList}
        cityCoordinates={cityCoordinates}
      />
      <Suspense fallback={null}>
        <TrackingSDK
          pageData={pageTrackingData}
          hotelInfo={hotelsTrackingData}
        />
      </Suspense>
    </>
  )
}
