"use client"

import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useCallback, useEffect, useMemo, useState } from "react"
import { useIntl } from "react-intl"

import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { trackLowestRoomPrice } from "@/utils/tracking"
import { convertObjToSearchParams } from "@/utils/url"

import RateSummary from "../RateSummary"
import { RoomSelectionPanel } from "../RoomSelectionPanel"
import { filterDuplicateRoomTypesByLowestPrice, parseRoomParams } from "./utils"

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

import {
  type DefaultFilterOptions,
  RoomPackageCodeEnum,
  type RoomPackageCodes,
} from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
import type {
  Rate,
  RateCode,
} from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomConfiguration } from "@/server/routers/hotels/output"

export default function Rooms({
  roomsAvailability,
  roomCategories = [],
  availablePackages,
  hotelType,
  isUserLoggedIn,
}: SelectRateProps) {
  const router = useRouter()
  const pathname = usePathname()
  const searchParams = useSearchParams()

  const hotelId = searchParams.get("hotel")
  const arrivalDate = searchParams.get("fromDate")
  const departureDate = searchParams.get("toDate")

  const searchedRoomsAndGuests = useMemo(
    () => parseRoomParams(searchParams),
    [searchParams]
  )

  const isMultipleRooms = searchedRoomsAndGuests.length > 1

  const intl = useIntl()

  const visibleRooms: RoomConfiguration[] = useMemo(() => {
    const deduped = filterDuplicateRoomTypesByLowestPrice(
      roomsAvailability.roomConfigurations
    )

    const separated = deduped.reduce<{
      available: RoomConfiguration[]
      notAvailable: RoomConfiguration[]
    }>(
      (acc, curr) => {
        if (curr.status === "NotAvailable") {
          return { ...acc, notAvailable: [...acc.notAvailable, curr] }
        }
        return { ...acc, available: [...acc.available, curr] }
      },
      { available: [], notAvailable: [] }
    )

    return [...separated.available, ...separated.notAvailable]
  }, [roomsAvailability.roomConfigurations])

  const [selectedRate, setSelectedRate] = useState<RateCode | undefined>(
    undefined
  )
  const [selectedPackages, setSelectedPackages] = useState<RoomPackageCodes[]>(
    []
  )

  const defaultPackages: DefaultFilterOptions[] = useMemo(
    () => [
      {
        code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
        description: intl.formatMessage({ id: "Accessible Room" }),
        itemCode: availablePackages.find(
          (pkg) => pkg.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM
        )?.itemCode,
      },
      {
        code: RoomPackageCodeEnum.ALLERGY_ROOM,
        description: intl.formatMessage({ id: "Allergy Room" }),
        itemCode: availablePackages.find(
          (pkg) => pkg.code === RoomPackageCodeEnum.ALLERGY_ROOM
        )?.itemCode,
      },
      {
        code: RoomPackageCodeEnum.PET_ROOM,
        description: intl.formatMessage({ id: "Pet Room" }),
        itemCode: availablePackages.find(
          (pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
        )?.itemCode,
      },
    ],
    [availablePackages, intl]
  )

  const handleFilter = useCallback(
    (filter: Record<RoomPackageCodeEnum, boolean | undefined>) => {
      const filteredPackages = Object.keys(filter).filter(
        (key) => filter[key as RoomPackageCodeEnum]
      ) as RoomPackageCodeEnum[]

      setSelectedPackages(filteredPackages)
    },
    []
  )

  const filteredRooms = useMemo(() => {
    return visibleRooms.filter((room) =>
      selectedPackages.every((filteredPackage) =>
        room.features.some((feature) => feature.code === filteredPackage)
      )
    )
  }, [visibleRooms, selectedPackages])

  const rooms = useMemo(() => {
    if (selectedPackages.length === 0) {
      return {
        ...roomsAvailability,
        roomConfigurations: visibleRooms,
      }
    }

    return {
      ...roomsAvailability,
      roomConfigurations: [...filteredRooms],
    }
  }, [roomsAvailability, visibleRooms, selectedPackages, filteredRooms])

  const rateSummary: Rate | null = useMemo(() => {
    const room = filteredRooms.find(
      (room) => room.roomTypeCode === selectedRate?.roomTypeCode
    )

    if (!room) return null

    const product = room.products.find(
      (product) =>
        product.productType.public.rateCode === selectedRate?.publicRateCode
    )

    if (!product) return null

    const petRoomPackage =
      (selectedPackages.includes(RoomPackageCodeEnum.PET_ROOM) &&
        availablePackages.find(
          (pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
        )) ||
      undefined

    const features = filteredRooms.find((room) =>
      room.features.some(
        (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM
      )
    )?.features

    const roomType = roomCategories.find((roomCategory) =>
      roomCategory.roomTypes.some(
        (roomType) => roomType.code === room.roomTypeCode
      )
    )

    const rateSummary: Rate = {
      features: petRoomPackage && features ? features : [],
      priceName: selectedRate?.name,
      priceTerm: selectedRate?.paymentTerm,
      public: product.productType.public,
      member: product.productType.member,
      roomType: roomType?.name || room.roomType,
      roomTypeCode: room.roomTypeCode,
    }

    return rateSummary
  }, [
    filteredRooms,
    availablePackages,
    selectedPackages,
    selectedRate,
    roomCategories,
  ])

  useEffect(() => {
    if (rateSummary) return
    if (!selectedRate) return

    setSelectedRate(undefined)
  }, [rateSummary, selectedRate])

  useEffect(() => {
    const pricesWithCurrencies = rooms.roomConfigurations.flatMap((room) =>
      room.products.map((product) => ({
        price: product.productType.public.localPrice.pricePerNight,
        currency: product.productType.public.localPrice.currency,
      }))
    )

    const cheapestPrice = pricesWithCurrencies.reduce(
      (minPrice, { price }) => Math.min(minPrice, price),
      Infinity
    )

    const currency = pricesWithCurrencies.find(
      ({ price }) => price === cheapestPrice
    )?.currency

    trackLowestRoomPrice({
      hotelId,
      arrivalDate,
      departureDate,
      lowestPrice: cheapestPrice,
      currency: currency,
    })
  }, [arrivalDate, departureDate, hotelId, rooms.roomConfigurations])

  const queryParams = useMemo(() => {
    // TODO: handle multiple rooms
    const newSearchParams = convertObjToSearchParams(
      {
        rooms: [
          {
            roomTypeCode: rateSummary?.roomTypeCode,
            rateCode: rateSummary?.public.rateCode,
            counterRateCode: rateSummary?.member?.rateCode,
            packages: selectedPackages,
          },
        ],
      },
      searchParams
    )

    return newSearchParams
  }, [searchParams, rateSummary, selectedPackages])

  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault()

    window.history.replaceState(
      null,
      "",
      `${pathname}?${queryParams.toString()}`
    )
    router.push(`select-bed?${queryParams}`)
  }

  return (
    <div className={styles.content}>
      {isMultipleRooms ? (
        searchedRoomsAndGuests.map((room, index) => (
          <div key={index}>
            <Subtitle>
              {intl.formatMessage(
                {
                  id: room.children?.length
                    ? "Room {roomIndex}, {adults} adults, {children} children"
                    : "Room {roomIndex}, {adults} adults",
                },
                {
                  roomIndex: index + 1,
                  adults: room.adults,
                  children: room.children?.length,
                }
              )}
            </Subtitle>
            <RoomSelectionPanel
              rooms={rooms}
              roomCategories={roomCategories}
              availablePackages={availablePackages}
              selectedPackages={selectedPackages}
              setSelectedRate={setSelectedRate}
              hotelType={hotelType}
              handleFilter={handleFilter}
              defaultPackages={defaultPackages}
            />
          </div>
        ))
      ) : (
        <RoomSelectionPanel
          rooms={rooms}
          roomCategories={roomCategories}
          availablePackages={availablePackages}
          selectedPackages={selectedPackages}
          setSelectedRate={setSelectedRate}
          hotelType={hotelType}
          handleFilter={handleFilter}
          defaultPackages={defaultPackages}
        />
      )}

      {rateSummary && (
        <form
          method="GET"
          action={`select-bed?${searchParams}`}
          onSubmit={handleSubmit}
        >
          <RateSummary
            rateSummary={rateSummary}
            isUserLoggedIn={isUserLoggedIn}
            packages={availablePackages}
            roomsAvailability={roomsAvailability}
          />
        </form>
      )}
    </div>
  )
}
