"use client"

import { useSession } from "next-auth/react"
import { createElement } from "react"
import { useIntl } from "react-intl"

import { useRatesStore } from "@/stores/select-rate"

import ToggleSidePeek from "@/components/HotelReservation/EnterDetails/SelectedRoom/ToggleSidePeek"
import { getRates } from "@/components/HotelReservation/SelectRate/utils"
import { getIconForFeatureCode } from "@/components/HotelReservation/utils"
import { ErrorCircleIcon } from "@/components/Icons"
import ImageGallery from "@/components/ImageGallery"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { useRoomContext } from "@/contexts/Room"
import { isValidClientSession } from "@/utils/clientSession"
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"

import { cardVariants } from "./cardVariants"
import FlexibilityOption from "./FlexibilityOption"
import RoomSize from "./RoomSize"

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

import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import type { RoomCardProps } from "@/types/components/hotelReservation/selectRate/roomCard"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import { HotelTypeEnum } from "@/types/enums/hotelType"
import type { Product } from "@/types/trpc/routers/hotel/roomAvailability"

function getBreakfastMessage(
  publicBreakfastIncluded: boolean,
  memberBreakfastIncluded: boolean,
  hotelType: string | undefined,
  userIsLoggedIn: boolean,
  msgs: Record<"included" | "noSelection" | "scandicgo" | "notIncluded", string>
) {
  if (hotelType === HotelTypeEnum.ScandicGo) {
    return msgs.scandicgo
  }

  if (userIsLoggedIn && memberBreakfastIncluded) {
    return msgs.included
  }

  if (publicBreakfastIncluded && memberBreakfastIncluded) {
    return msgs.included
  }

  /** selected and rate does not include breakfast */
  if (false) {
    return msgs.notIncluded
  }

  if (!publicBreakfastIncluded && !memberBreakfastIncluded) {
    return msgs.notIncluded
  }

  return msgs.noSelection
}

export default function RoomCard({ roomConfiguration }: RoomCardProps) {
  const { data: session } = useSession()
  const isUserLoggedIn = isValidClientSession(session)
  const intl = useIntl()
  const lessThanFiveRoomsLeft =
    roomConfiguration.roomsLeft > 0 && roomConfiguration.roomsLeft < 5

  const {
    hotelId,
    hotelType,
    petRoomPackage,
    rateDefinitions,
    roomCategories,
  } = useRatesStore((state) => ({
    hotelId: state.booking.hotelId,
    hotelType: state.hotelType,
    petRoomPackage: state.petRoomPackage,
    rateDefinitions: state.roomsAvailability?.rateDefinitions,
    roomCategories: state.roomCategories,
  }))
  const { selectedPackage, selectedRate } = useRoomContext()

  const classNames = cardVariants({
    availability:
      roomConfiguration.status === AvailabilityEnum.NotAvailable
        ? "noAvailability"
        : "default",
  })

  const breakfastMessages = {
    included: intl.formatMessage({ id: "Breakfast is included." }),
    notIncluded: intl.formatMessage({
      id: "Breakfast selection in next step.",
    }),
    noSelection: intl.formatMessage({ id: "Select a rate" }),
    scandicgo: intl.formatMessage({
      id: "Breakfast deal can be purchased at the hotel.",
    }),
  }
  const breakfastMessage = getBreakfastMessage(
    roomConfiguration.breakfastIncludedInAllRatesPublic,
    roomConfiguration.breakfastIncludedInAllRatesMember,
    hotelType,
    isUserLoggedIn,
    breakfastMessages
  )

  if (!rateDefinitions) {
    return null
  }

  const rates = getRates(rateDefinitions)

  const petRoomPackageSelected =
    (selectedPackage === RoomPackageCodeEnum.PET_ROOM && petRoomPackage) ||
    undefined

  const selectedRoom = roomCategories.find((roomCategory) =>
    roomCategory.roomTypes.find(
      (roomType) => roomType.code === roomConfiguration.roomTypeCode
    )
  )

  const { name, roomSize, totalOccupancy, images } = selectedRoom || {}
  const galleryImages = mapApiImagesToGalleryImages(images || [])

  const freeCancelation = intl.formatMessage({ id: "Free cancellation" })
  const nonRefundable = intl.formatMessage({ id: "Non-refundable" })
  const freeBooking = intl.formatMessage({ id: "Free rebooking" })
  const payLater = intl.formatMessage({ id: "Pay later" })
  const payNow = intl.formatMessage({ id: "Pay now" })

  function getRate(rateCode: string) {
    switch (rateCode) {
      case "change":
        return {
          isFlex: false,
          notAvailable: false,
          title: freeBooking,
        }
      case "flex":
        return {
          isFlex: true,
          notAvailable: false,
          title: freeCancelation,
        }
      case "save":
        return {
          isFlex: false,
          notAvailable: false,
          title: nonRefundable,
        }
      default:
        throw new Error(
          `Unknown key for rate, should be "change", "flex" or "save", but got ${rateCode}`
        )
    }
  }

  function getRateInfo(product: Product) {
    if (
      !product.productType.public.rateCode &&
      !product.productType.member?.rateCode
    ) {
      const possibleRate = getRate(product.productType.public.rate)
      if (possibleRate) {
        return {
          ...possibleRate,
          notAvailable: true,
        }
      }
      return {
        isFlex: false,
        notAvailable: true,
        title: "",
      }
    }

    const publicRate = Object.keys(rates).find((k) =>
      rates[k as keyof typeof rates].find(
        (a) => a.rateCode === product.productType.public.rateCode
      )
    )
    let memberRate
    if (product.productType.member) {
      memberRate = Object.keys(rates).find((k) =>
        rates[k as keyof typeof rates].find(
          (a) => a.rateCode === product.productType.member!.rateCode
        )
      )
    }

    if (!publicRate || !memberRate) {
      throw new Error("We should never make it where without rateCodes")
    }

    const key = isUserLoggedIn ? memberRate : publicRate
    return getRate(key)
  }

  return (
    <li className={classNames}>
      <div>
        <div className={styles.imageContainer}>
          <div className={styles.chipContainer}>
            {lessThanFiveRoomsLeft ? (
              <span className={styles.chip}>
                <Footnote color="burgundy" textTransform="uppercase">
                  {intl.formatMessage(
                    { id: "{amount, number} left" },
                    { amount: roomConfiguration.roomsLeft }
                  )}
                </Footnote>
              </span>
            ) : null}
            {roomConfiguration.features
              .filter((feature) => selectedPackage === feature.code)
              .map((feature) => (
                <span className={styles.chip} key={feature.code}>
                  {createElement(getIconForFeatureCode(feature.code), {
                    color: "burgundy",
                    height: 16,
                    width: 16,
                  })}
                </span>
              ))}
          </div>
          <ImageGallery
            images={galleryImages}
            title={roomConfiguration.roomType}
            fill
          />
        </div>

        <div className={styles.specification}>
          {totalOccupancy && (
            <Caption color="uiTextMediumContrast" className={styles.guests}>
              {intl.formatMessage(
                {
                  id: "Max {max, plural, one {{range} guest} other {{range} guests}}",
                },
                { max: totalOccupancy.max, range: totalOccupancy.range }
              )}
            </Caption>
          )}
          <RoomSize roomSize={roomSize} />
          <div className={styles.toggleSidePeek}>
            {roomConfiguration.roomTypeCode && (
              <ToggleSidePeek
                hotelId={hotelId.toString()}
                roomTypeCode={roomConfiguration.roomTypeCode}
              />
            )}
          </div>
        </div>
        <div className={styles.roomDetails}>
          <Subtitle className={styles.name} type="two">
            {name}
          </Subtitle>
          {/* Out of scope for now
            <Body>{descriptions?.short}</Body>
            */}
        </div>
      </div>

      <div className={styles.container}>
        {roomConfiguration.status === AvailabilityEnum.NotAvailable ? (
          <div className={styles.noRoomsContainer}>
            <div className={styles.noRooms}>
              <ErrorCircleIcon color="red" width={16} />
              <Caption color="uiTextHighContrast" type="bold">
                {intl.formatMessage({
                  id: "This room is not available",
                })}
              </Caption>
            </div>
          </div>
        ) : (
          <>
            <Caption color="uiTextHighContrast" type="bold">
              {breakfastMessage}
            </Caption>
            {roomConfiguration.products.map((product) => {
              const rate = getRateInfo(product)
              const isSelectedRateCode =
                selectedRate?.product.productType.public.rateCode ===
                  product.productType.public.rateCode ||
                selectedRate?.product.productType.member?.rateCode ===
                  product.productType.member?.rateCode
              return (
                <FlexibilityOption
                  key={product.productType.public.rateCode}
                  features={roomConfiguration.features}
                  isSelected={
                    isSelectedRateCode &&
                    selectedRate?.roomTypeCode ===
                      roomConfiguration.roomTypeCode
                  }
                  isUserLoggedIn={isUserLoggedIn}
                  paymentTerm={rate.isFlex ? payLater : payNow}
                  petRoomPackage={petRoomPackageSelected}
                  product={rate.notAvailable ? undefined : product}
                  roomType={roomConfiguration.roomType}
                  roomTypeCode={roomConfiguration.roomTypeCode}
                  title={rate.title}
                />
              )
            })}
          </>
        )}
      </div>
    </li>
  )
}
