'use client'

import { Map, type MapProps, useMap } from '@vis.gl/react-google-maps'
import { useEffect, useState } from 'react'
import { useIntl } from 'react-intl'

import { IconButton } from '../../IconButton'
import { MaterialIcon } from '../../Icons/MaterialIcon'

import { HOTEL_PAGE, MAP_RESTRICTIONS } from '../mapConstants'

import { useZoomControls } from '@scandic-hotels/common/hooks/map/useZoomControls'

import { HotelListingMapContent } from './HotelListingMapContent'
import PoiMapMarkers from './PoiMapMarkers'

import styles from './interactiveMap.module.css'

import { CurrencyEnum } from '@scandic-hotels/common/constants/currency'
import { Lang } from '@scandic-hotels/common/constants/language'
import { HotelPin, MarkerInfo, PointOfInterest } from '../types'

export type InteractiveMapProps = {
  lang: Lang
  coordinates: {
    lat: number
    lng: number
  }
  activePoi?: string | null
  hotelPins?: HotelPin[]
  pointsCurrency?: CurrencyEnum
  pointsOfInterest?: PointOfInterest[]
  markerInfo?: MarkerInfo
  mapId: string
  closeButton: React.ReactNode
  fitBounds?: boolean
  hoveredHotelPin?: string | null
  activeHotelPin?: string | null

  isUserLoggedIn: boolean
  onTilesLoaded?: () => void
  onActivePoiChange?: (poi: string | null) => void

  onClickHotel?: (hotelId: string) => void

  /**
   * Called when a hotel pin is hovered.
   * @param args when null, it means the hover has ended
   * @returns
   */
  onHoverHotelPin?: (
    args: { hotelName: string; hotelId: string } | null
  ) => void

  /**
   * Called when a hotel pin is activated.
   * @param args when null, it means nothing is active
   * @returns
   */
  onSetActiveHotelPin?: (
    args: { hotelName: string; hotelId: string } | null
  ) => void
}

export function InteractiveMap({
  lang,
  coordinates,
  pointsOfInterest,
  activePoi,
  hotelPins,
  mapId,
  closeButton,
  markerInfo,
  fitBounds = true,
  hoveredHotelPin,
  activeHotelPin,
  isUserLoggedIn,
  pointsCurrency,
  onClickHotel,
  onHoverHotelPin,
  onSetActiveHotelPin,
  onTilesLoaded,
  onActivePoiChange,
}: InteractiveMapProps) {
  const intl = useIntl()
  const map = useMap()
  const [hasInitializedBounds, setHasInitializedBounds] = useState(false)
  const { zoomIn, zoomOut, isMaxZoom, isMinZoom } = useZoomControls(HOTEL_PAGE)

  const mapOptions: MapProps = {
    defaultZoom: HOTEL_PAGE.DEFAULT_ZOOM,
    minZoom: HOTEL_PAGE.MIN_ZOOM,
    maxZoom: HOTEL_PAGE.MAX_ZOOM,
    defaultCenter: coordinates,
    disableDefaultUI: true,
    clickableIcons: false,
    mapId,
    gestureHandling: 'greedy',
    restriction: MAP_RESTRICTIONS,
  }

  useEffect(() => {
    if (map && hotelPins?.length && !hasInitializedBounds) {
      if (fitBounds) {
        const bounds = new google.maps.LatLngBounds()
        hotelPins.forEach((marker) => {
          bounds.extend(marker.coordinates)
        })
        map.fitBounds(bounds, 100)
      }
      setHasInitializedBounds(true)
    }
  }, [map, fitBounds, hotelPins, hasInitializedBounds])

  return (
    <div className={styles.mapContainer}>
      <Map {...mapOptions} onTilesLoaded={onTilesLoaded}>
        {hotelPins && (
          <HotelListingMapContent
            lang={lang}
            isUserLoggedIn={isUserLoggedIn}
            hotelPins={hotelPins}
            setActiveHotel={onSetActiveHotelPin}
            setHoveredHotel={onHoverHotelPin}
            activeHotel={activeHotelPin}
            hoveredHotel={hoveredHotelPin}
            onClickHotel={onClickHotel}
            pointsCurrency={pointsCurrency}
          />
        )}
        {pointsOfInterest && markerInfo && (
          <PoiMapMarkers
            coordinates={coordinates}
            pointsOfInterest={pointsOfInterest}
            onActivePoiChange={onActivePoiChange}
            activePoi={activePoi}
            markerInfo={markerInfo}
          />
        )}
      </Map>
      <div className={styles.ctaButtons}>
        {closeButton}
        <div className={styles.zoomButtons}>
          <IconButton
            variant="Elevated"
            className={styles.zoomButton}
            onClick={zoomOut}
            aria-label={intl.formatMessage({
              id: 'map.zoomOut',
              defaultMessage: 'Zoom out',
            })}
            isDisabled={isMinZoom}
          >
            <MaterialIcon icon="remove" color="CurrentColor" />
          </IconButton>

          <IconButton
            variant="Elevated"
            className={styles.zoomButton}
            onClick={zoomIn}
            aria-label={intl.formatMessage({
              id: 'map.zoomIn',
              defaultMessage: 'Zoom in',
            })}
            isDisabled={isMaxZoom}
          >
            <MaterialIcon icon="add" color="CurrentColor" />
          </IconButton>
        </div>
      </div>
    </div>
  )
}
