"use client"

import { TRPCClientError } from "@trpc/client"
import { useEffect } from "react"
import { useIntl } from "react-intl"

import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { Alert } from "@scandic-hotels/design-system/Alert"
import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"

import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateContext"
import useLang from "../../../hooks/useLang"
import { mapPackageToLabel } from "../../../utils/getRoomFeatureDescription"
import { trackLowestRoomPrice, trackRoomsLoaded } from "../Tracking/tracking"
import { RateSummary } from "./RateSummary"
import Rooms from "./Rooms"
import { RoomsContainerSkeleton } from "./RoomsContainerSkeleton"

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

import type { HotelData } from "@scandic-hotels/trpc/types/hotel"

interface RoomsContainerProps
  extends Pick<HotelData, "roomCategories">,
    Pick<HotelData["hotel"], "hotelType" | "vat"> {}

export function RoomsContainer({}: RoomsContainerProps) {
  const intl = useIntl()
  const lang = useLang()

  const {
    hotel,
    availability: { error, isFetching, isError, data: availabilityData },
    input: { hasError: hasInputError, errorCode, data: inputData },
    getLowestRoomPrice,
  } = useSelectRateContext()

  const { price: lowestRoomPrice, currency: lowestRoomPriceCurrency } =
    getLowestRoomPrice() ?? {}
  const dataAvailable = availabilityData?.length
  const { hotelId, fromDate, toDate, bookingCode, searchType, rooms } =
    inputData?.booking ?? {}

  const specialRoomType = rooms
    ?.map((room) => {
      const packages = room.packages
        ?.map((pkg) => {
          mapPackageToLabel(pkg)
        })
        .join(",")

      return packages ?? ""
    })
    .join("|")

  useEffect(() => {
    if (!dataAvailable) return

    if (!hotelId || !fromDate || !toDate || !lowestRoomPrice) return

    trackLowestRoomPrice({
      hotelId: hotelId,
      arrivalDate: fromDate,
      departureDate: toDate,
      lowestPrice: lowestRoomPrice.toString(),
      currency: lowestRoomPriceCurrency,
    })
  }, [
    dataAvailable,
    hotelId,
    fromDate,
    toDate,
    lowestRoomPrice,
    lowestRoomPriceCurrency,
  ])

  useEffect(() => {
    if (isFetching) return
    trackRoomsLoaded()
  }, [isFetching])

  useEffect(() => {
    if (isFetching || !availabilityData || !toDate || !fromDate) return
    const shouldTrackNoAvailability = availabilityData.some((room) => {
      if (!room || "error" in room) return false

      return room.roomConfigurations.every(
        (roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
      )
    })
    if (shouldTrackNoAvailability) {
      trackNoAvailability({
        specialRoomType,
        searchTerm: hotel.data?.additionalData?.name || "",
        lang,
        fromDate,
        toDate,
        noOfRooms: rooms?.length,
        searchType: "hotel",
        hotelId,
        rewardNight: searchType === SEARCH_TYPE_REDEMPTION ? "yes" : "no",
        bookingCode,
        pageId: "select-rate",
        pageName: "hotelreservation|select-rate",
        pageType: "bookingroomsandratespage",
        siteSections: "hotelreservation|select-rate",
        domain: typeof window !== "undefined" ? window.location.host : "",
      })
    }
  }, [
    isFetching,
    availabilityData,
    bookingCode,
    hotelId,
    fromDate,
    toDate,
    specialRoomType,
    hotel.data?.additionalData?.name,
    rooms?.length,
    searchType,
    lang,
  ])

  if (isFetching) {
    return <RoomsContainerSkeleton />
  }

  if (isError || hasInputError) {
    const errorMessage = getErrorMessage(error ?? errorCode, intl)

    return (
      <div className={styles.errorContainer}>
        <Alert type={AlertTypeEnum.Alarm} heading={errorMessage} />
      </div>
    )
  }

  return (
    <>
      <Rooms />
      <RateSummary />
    </>
  )
}

function getErrorMessage(error: unknown, intl: ReturnType<typeof useIntl>) {
  let errorCode = ""
  if (error instanceof TRPCClientError) {
    errorCode = error.data?.zodError?.formErrors?.at(0)
  } else if (typeof error == "string") {
    errorCode = error
  }

  switch (errorCode) {
    case "FROMDATE_INVALID":
    case "TODATE_INVALID":
    case "TODATE_MUST_BE_AFTER_FROMDATE":
    case "FROMDATE_CANNOT_BE_IN_THE_PAST": {
      return intl.formatMessage({
        id: "selectRate.invalidDatesErrorMessage",
        defaultMessage: "Invalid dates",
      })
    }
    default:
      return intl.formatMessage({
        id: "errorMessage.somethingWentWrong",
        defaultMessage: "Something went wrong!",
      })
  }
}
