"use client"
import { useMap } from "@vis.gl/react-google-maps"
import { useCallback, useMemo, useRef, useState } from "react"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"

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

import { selectHotel } from "@/constants/routes/hotelReservation"
import { useBookingCodeFilterStore } from "@/stores/bookingCode-filter"
import { useHotelFilterStore } from "@/stores/hotel-filters"
import { useHotelsMapStore } from "@/stores/hotels-map"

import { RoomCardSkeleton } from "@/components/HotelReservation/RoomCardSkeleton/RoomCardSkeleton"
import InteractiveMap from "@/components/Maps/InteractiveMap"
import { BackToTopButton } from "@/components/TempDesignSystem/BackToTopButton"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang"
import { useScrollToTop } from "@/hooks/useScrollToTop"
import { debounce } from "@/utils/debounce"

import BookingCodeFilter from "../../BookingCodeFilter"
import FilterAndSortModal from "../../FilterAndSortModal"
import HotelListing from "../HotelListing"
import { getVisibleHotels } from "./utils"

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

import type { SelectHotelMapProps } from "@/types/components/hotelReservation/selectHotel/map"
import { BookingCodeFilterEnum } from "@/types/enums/bookingCodeFilter"
import { RateTypeEnum } from "@/types/enums/rateType"
import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/helpers"

const SKELETON_LOAD_DELAY = 750

export default function SelectHotelContent({
  hotelPins,
  cityCoordinates,
  mapId,
  hotels,
  filterList,
  bookingCode,
  isBookingCodeRateAvailable,
}: Omit<SelectHotelMapProps, "apiKey">) {
  const lang = useLang()
  const intl = useIntl()
  const map = useMap()

  const isAboveMobile = useMediaQuery("(min-width: 768px)")
  const [visibleHotels, setVisibleHotels] = useState<HotelResponse[]>([])
  const [showSkeleton, setShowSkeleton] = useState<boolean>(true)
  const listingContainerRef = useRef<HTMLDivElement | null>(null)

  const activeFilters = useHotelFilterStore((state) => state.activeFilters)
  const { activeHotel } = useHotelsMapStore()

  const { showBackToTop, scrollToTop } = useScrollToTop({
    threshold: 490,
    elementRef: listingContainerRef,
    refScrollable: true,
  })
  const activeCodeFilter = useBookingCodeFilterStore(
    (state) => state.activeCodeFilter
  )

  const coordinates = useMemo(() => {
    if (activeHotel) {
      const hotel = hotels.find((hotel) => hotel.hotel.name === activeHotel)

      if (hotel && hotel.hotel.location) {
        return {
          lat: hotel.hotel.location.latitude,
          lng: hotel.hotel.location.longitude,
        }
      }
    }

    return isAboveMobile
      ? cityCoordinates
      : { ...cityCoordinates, lat: cityCoordinates.lat - 0.006 }
  }, [activeHotel, hotels, isAboveMobile, cityCoordinates])

  const filteredHotelPins = useMemo(() => {
    const updatedHotelsList = bookingCode
      ? hotelPins.filter(
          (hotel) =>
            !hotel.publicPrice ||
            activeCodeFilter === BookingCodeFilterEnum.All ||
            (activeCodeFilter === BookingCodeFilterEnum.Discounted &&
              hotel.rateType !== RateTypeEnum.Regular) ||
            (activeCodeFilter === BookingCodeFilterEnum.Regular &&
              hotel.rateType === RateTypeEnum.Regular)
        )
      : hotelPins
    return updatedHotelsList.filter((hotel) =>
      activeFilters.every((filterId) =>
        hotel.facilityIds.includes(Number(filterId))
      )
    )
  }, [activeFilters, hotelPins, bookingCode, activeCodeFilter])

  const getHotelCards = useCallback(() => {
    const visibleHotels = getVisibleHotels(hotels, filteredHotelPins, map)
    setVisibleHotels(visibleHotels)
    setTimeout(() => {
      setShowSkeleton(false)
    }, SKELETON_LOAD_DELAY)
  }, [hotels, filteredHotelPins, map])

  /**
   * Updates visible hotels when map viewport changes (zoom/pan)
   * - Debounces updates to prevent excessive re-renders during map interaction
   * - Shows loading skeleton while map tiles load
   * - Triggers on: initial load, zoom, pan, and tile loading completion
   */
  const debouncedUpdateHotelCards = useMemo(
    () =>
      debounce(() => {
        if (!map) return
        if (isAboveMobile) {
          setShowSkeleton(true)
        }
        getHotelCards()
      }, 100),
    [map, getHotelCards, isAboveMobile]
  )

  const closeButton = (
    <Button
      intent="inverted"
      size="small"
      theme="base"
      className={styles.closeButton}
      asChild
    >
      <Link href={selectHotel(lang)} keepSearchParams prefetch>
        <MaterialIcon icon="close" size={20} color="CurrentColor" />
        {intl.formatMessage({
          defaultMessage: "Close the map",
        })}
      </Link>
    </Button>
  )

  const isRegularRateAvailable = bookingCode
    ? hotels.some(
        (hotel) =>
          hotel.availability.productType?.public?.rateType ===
            RateTypeEnum.Regular ||
          hotel.availability.productType?.member?.rateType ===
            RateTypeEnum.Regular
      )
    : false

  return (
    <div className={styles.container}>
      <div className={styles.listingContainer} ref={listingContainerRef}>
        <div className={styles.filterContainer}>
          <Button
            intent="text"
            type="button"
            variant="icon"
            size="small"
            className={styles.filterContainerCloseButton}
            asChild
          >
            <Link href={selectHotel(lang)} keepSearchParams>
              <MaterialIcon icon="arrow_back" color="CurrentColor" size={20} />
              {intl.formatMessage({ defaultMessage: "Back" })}
            </Link>
          </Button>
          <FilterAndSortModal
            filters={filterList}
            setShowSkeleton={setShowSkeleton}
          />
          {bookingCode &&
          isBookingCodeRateAvailable &&
          isRegularRateAvailable ? (
            <BookingCodeFilter />
          ) : null}
        </div>

        {showSkeleton ? (
          <div className={styles.skeletonContainer}>
            <RoomCardSkeleton />
            <RoomCardSkeleton />
          </div>
        ) : (
          <HotelListing hotels={visibleHotels} />
        )}
        {showBackToTop && (
          <BackToTopButton position="left" onClick={scrollToTop} />
        )}
      </div>
      <InteractiveMap
        closeButton={closeButton}
        coordinates={coordinates}
        hotelPins={filteredHotelPins}
        mapId={mapId}
        onTilesLoaded={debouncedUpdateHotelCards}
      />
    </div>
  )
}
