import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { notFound } from "next/navigation"

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

import {
  fetchAlternativeHotels,
  fetchAvailableHotels,
  fetchBookingCodeAvailableHotels,
  getFiltersFromHotels,
} from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils"
import { getHotelSearchDetails } from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/utils"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
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 } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelMapContainerProps } from "@/types/components/hotelReservation/selectHotel/map"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import {
  TrackingChannelEnum,
  type TrackingSDKHotelInfo,
  type TrackingSDKPageData,
} from "@/types/components/tracking"

export async function SelectHotelMapContainer({
  searchParams,
  isAlternativeHotels,
}: SelectHotelMapContainerProps) {
  const lang = getLang()
  const intl = await getIntl()
  const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID
  const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY
  const getHotelSearchDetailsPromise = safeTry(
    getHotelSearchDetails(
      {
        searchParams: searchParams as SelectHotelSearchParams & {
          [key: string]: string
        },
      },
      isAlternativeHotels
    )
  )

  const [searchDetails] = await getHotelSearchDetailsPromise

  if (!searchDetails) return notFound()

  const {
    city,
    selectHotelParams,
    adultsInRoom,
    childrenInRoom,
    childrenInRoomString,
    hotel: isAlternativeFor,
    bookingCode,
    redemption,
  } = searchDetails

  if (!city) return notFound()

  const fetchAvailableHotelsPromise = isAlternativeFor
    ? safeTry(
        fetchAlternativeHotels(isAlternativeFor.id, {
          roomStayStartDate: selectHotelParams.fromDate,
          roomStayEndDate: selectHotelParams.toDate,
          adults: adultsInRoom[0],
          children: childrenInRoomString,
          bookingCode,
          redemption,
        })
      )
    : bookingCode
      ? safeTry(
          fetchBookingCodeAvailableHotels({
            cityId: city.id,
            roomStayStartDate: selectHotelParams.fromDate,
            roomStayEndDate: selectHotelParams.toDate,
            adults: adultsInRoom[0],
            children: childrenInRoomString,
            bookingCode,
          })
        )
      : safeTry(
          fetchAvailableHotels({
            cityId: city.id,
            roomStayStartDate: selectHotelParams.fromDate,
            roomStayEndDate: selectHotelParams.toDate,
            adults: adultsInRoom[0],
            children: childrenInRoomString,
            redemption,
          })
        )

  const [hotels] = await fetchAvailableHotelsPromise

  const validHotels = (hotels?.filter(Boolean) as HotelData[]) || []

  const currencyValue = redemption
    ? intl.formatMessage({ id: "Points" })
    : undefined
  const hotelPins = getHotelPins(validHotels, currencyValue)
  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: isAlternativeFor ? "alternative-hotels" : "select-hotel",
    domainLanguage: lang,
    channel: TrackingChannelEnum["hotelreservation"],
    pageName: isAlternativeHotels
      ? "hotelreservation|alternative-hotels|mapview"
      : "hotelreservation|select-hotel|mapview",
    siteSections: isAlternativeHotels
      ? "hotelreservation|altervative-hotels|mapview"
      : "hotelreservation|select-hotel|mapview",
    pageType: "bookinghotelsmapviewpage",
    siteVersion: "new-web",
  }

  const hotelsTrackingData: TrackingSDKHotelInfo = {
    availableResults: validHotels.length,
    searchTerm: isAlternativeFor
      ? selectHotelParams.hotelId
      : (selectHotelParams.city as string),
    arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
    departureDate: format(departureDate, "yyyy-MM-dd"),
    noOfAdults: adultsInRoom[0], // TODO: Handle multiple rooms
    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}
        bookingCode={bookingCode ?? ""}
      />
      <TrackingSDK pageData={pageTrackingData} hotelInfo={hotelsTrackingData} />
    </>
  )
}
