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

import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"

import { FamilyAndFriendsCodes } from "@/constants/booking"
import {
  alternativeHotels,
  alternativeHotelsMap,
  selectHotel,
  selectHotelMap,
} from "@/constants/routes/hotelReservation"

import StaticMap from "@/components/Maps/StaticMap"
import Breadcrumbs from "@/components/TempDesignSystem/Breadcrumbs"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
import { getHotelSearchDetails } from "@/utils/hotelSearchDetails"
import { convertObjToSearchParams } from "@/utils/url"

import FnFNotAllowedAlert from "../FnFNotAllowedAlert/FnFNotAllowedAlert"
import HotelCardListing from "../HotelCardListing"
import BookingCodeFilter from "./BookingCodeFilter"
import { getFiltersFromHotels, getHotels } from "./helpers"
import HotelCount from "./HotelCount"
import HotelFilter from "./HotelFilter"
import HotelSorter from "./HotelSorter"
import MobileMapButtonContainer from "./MobileMapButtonContainer"
import NoAvailabilityAlert from "./NoAvailabilityAlert"
import { getTracking } from "./tracking"

import styles from "./selectHotel.module.css"

import type { SelectHotelProps } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"

export default async function SelectHotel({
  params,
  searchParams,
  isAlternativeHotels,
}: SelectHotelProps) {
  const intl = await getIntl()

  const searchDetails = await getHotelSearchDetails(
    {
      searchParams: searchParams as SelectHotelSearchParams & {
        [key: string]: string
      },
    },
    isAlternativeHotels
  )

  if (!searchDetails) return notFound()

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

  if (!city) return notFound()

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

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

  const hotels = await getHotels(
    selectHotelParams,
    isAlternativeFor,
    bookingCode,
    city,
    !!redemption
  )

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

  const isCityWithCountry = (city: any): city is { country: string } =>
    "country" in city
  const filterList = getFiltersFromHotels(hotels)

  const convertedSearchParams = convertObjToSearchParams(selectHotelParams)
  const breadcrumbs = [
    {
      title: intl.formatMessage({
        defaultMessage: "Home",
      }),
      href: `/${params.lang}`,
      uid: "home-page",
    },
    {
      title: intl.formatMessage({
        defaultMessage: "Hotel reservation",
      }),
      href: `/${params.lang}/hotelreservation`,
      uid: "hotel-reservation",
    },
    isAlternativeFor
      ? {
          title: intl.formatMessage({
            defaultMessage: "Alternative hotels",
          }),
          href: `${alternativeHotels(params.lang)}/?${convertedSearchParams}`,
          uid: "alternative-hotels",
        }
      : {
          title: intl.formatMessage({
            defaultMessage: "Select hotel",
          }),
          href: `${selectHotel(params.lang)}/?${convertedSearchParams}`,
          uid: "select-hotel",
        },
    isAlternativeFor
      ? {
          title: isAlternativeFor.name,
          uid: isAlternativeFor.id,
        }
      : {
          title: city.name,
          uid: city.id,
        },
  ]

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

  const suspenseKey = stringify(searchParams)

  const isFullPriceHotelAvailable = bookingCode
    ? hotels?.some(
        (hotel) =>
          !hotel.availability.productType?.public?.bookingCode &&
          !hotel.availability.productType?.member?.bookingCode
      )
    : false

  const isBookingCodeRateAvailable = bookingCode
    ? hotels?.some(
        (hotel) =>
          hotel.availability.productType?.public?.bookingCode ||
          hotel.availability.productType?.member?.bookingCode
      )
    : false

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

  // Special rates (corporate cheque, voucher and reward nights) will not have regular rate hotels availability
  const isSpecialRate = hotels?.some(
    (hotel) =>
      hotel.availability.productType?.bonusCheque ||
      hotel.availability.productType?.voucher ||
      hotel.availability.productType?.redemptions
  )
  return (
    <>
      <header className={styles.header}>
        <div className={styles.headerContent}>
          <Breadcrumbs breadcrumbs={breadcrumbs} />
          <div className={styles.title}>
            <div className={styles.cityInformation}>
              <Subtitle>
                {isAlternativeFor
                  ? intl.formatMessage(
                      {
                        defaultMessage: "Alternatives for {value}",
                      },
                      {
                        value: isAlternativeFor.name,
                      }
                    )
                  : city.name}
              </Subtitle>
              <HotelCount />
            </div>
            <div className={styles.sorter}>
              <HotelSorter discreet />
            </div>
          </div>
          <MobileMapButtonContainer filters={filterList} />
        </div>
      </header>
      <main className={styles.main}>
        {isBookingCodeRateAvailable &&
        isFullPriceHotelAvailable &&
        !isSpecialRate ? (
          <BookingCodeFilter />
        ) : null}
        <div className={styles.sideBar}>
          {hotels.length ? (
            <Link
              className={styles.link}
              color="burgundy"
              href={
                isAlternativeFor
                  ? alternativeHotelsMap(params.lang)
                  : selectHotelMap(params.lang)
              }
              keepSearchParams
            >
              <div className={styles.mapContainer}>
                <StaticMap
                  city={city.name}
                  country={isCityWithCountry(city) ? city.country : undefined}
                  width={340}
                  height={180}
                  zoomLevel={11}
                  mapType="roadmap"
                  altText={`Map of ${city.name} city center`}
                />
                <Button wrapping size="medium" intent="text" theme="base">
                  {intl.formatMessage({
                    defaultMessage: "See map",
                  })}
                  <MaterialIcon
                    icon="chevron_right"
                    size={20}
                    color="CurrentColor"
                  />
                </Button>
              </div>
            </Link>
          ) : (
            <div className={styles.mapContainer}>
              <StaticMap
                city={city.name}
                width={340}
                height={180}
                zoomLevel={11}
                mapType="roadmap"
                altText={`Map of ${city.name} city center`}
              />
            </div>
          )}
          <HotelFilter filters={filterList} className={styles.filter} />
        </div>
        <div className={styles.hotelList}>
          <NoAvailabilityAlert
            hotelsLength={hotels.length}
            isAlternative={!!isAlternativeFor}
            isAllUnavailable={isAllUnavailable}
            operaId={hotels?.[0]?.hotel.operaId}
            bookingCode={bookingCode}
            isBookingCodeRateNotAvailable={!isBookingCodeRateAvailable}
          />
          <HotelCardListing hotelData={hotels} />
        </div>
      </main>
      <Suspense key={`${suspenseKey}-tracking`} fallback={null}>
        <TrackingSDK
          pageData={pageTrackingData}
          hotelInfo={hotelsTrackingData}
        />
      </Suspense>
    </>
  )
}
