"use client"

import "client-only"

import { Map, type MapProps, useMap } from "@vis.gl/react-google-maps"
import { cx } from "class-variance-authority"
import { type PropsWithChildren, useEffect, useRef, useState } from "react"
import { useIntl } from "react-intl"

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

import { MAP_RESTRICTIONS } from "@/constants/map"
import { useDestinationPageHotelsMapStore } from "@/stores/destination-page-hotels-map"

import ErrorBoundary from "@/components/ErrorBoundary/ErrorBoundary"
import Button from "@/components/TempDesignSystem/Button"
import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"

import { usePageType } from "../PageTypeProvider"

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

import type { DestinationMarker } from "@/types/components/maps/destinationMarkers"

const BACKUP_COORDINATES = {
  lat: 59.3293,
  lng: 18.0686,
}

interface DynamicMapProps {
  markers: DestinationMarker[]
  mapId: string
  defaultCenter?: google.maps.LatLngLiteral
  defaultZoom?: number
  fitBounds?: boolean
  boundsPadding?: number
  gestureHandling?: "greedy" | "cooperative" | "auto" | "none"
  onClose?: () => void
}

export default function DynamicMap({
  markers,
  mapId,
  defaultCenter = BACKUP_COORDINATES,
  defaultZoom = 3,
  fitBounds = true,
  boundsPadding = 100,
  onClose,
  gestureHandling = "auto",
  children,
}: PropsWithChildren<DynamicMapProps>) {
  const intl = useIntl()
  const map = useMap()
  const pageType = usePageType()
  const { activeMarker } = useDestinationPageHotelsMapStore()
  const ref = useRef<HTMLDivElement>(null)
  const [hasFittedBounds, setHasFittedBounds] = useState(!!activeMarker)

  useEffect(() => {
    if (ref.current && activeMarker && pageType === "overview") {
      ref.current.scrollIntoView({
        behavior: "smooth",
        block: "end",
      })
    }
  }, [activeMarker, pageType])

  useEffect(() => {
    if (map && fitBounds && markers?.length && !hasFittedBounds) {
      const bounds = new google.maps.LatLngBounds()
      markers.forEach((marker) => {
        bounds.extend(marker.coordinates)
      })
      map.fitBounds(bounds, boundsPadding)
      setHasFittedBounds(true)
    }
  }, [map, fitBounds, markers, hasFittedBounds, boundsPadding])

  useHandleKeyUp((event: KeyboardEvent) => {
    if (event.key === "Escape" && onClose) {
      onClose()
    }
  })

  function zoomIn() {
    const currentZoom = map && map.getZoom()
    if (currentZoom) {
      map.setZoom(currentZoom + 1)
    }
  }
  function zoomOut() {
    const currentZoom = map && map.getZoom()
    if (currentZoom) {
      map.setZoom(currentZoom - 1)
    }
  }

  const mapOptions: MapProps = {
    defaultCenter, // Default center will be overridden by the bounds
    minZoom: 3,
    maxZoom: 18,
    defaultZoom,
    disableDefaultUI: true,
    clickableIcons: false,
    gestureHandling,
    mapId,
    restriction: MAP_RESTRICTIONS,
  }

  return (
    <div
      className={cx(
        styles.mapWrapper,
        onClose && styles.mapWrapperWithCloseButton
      )}
      ref={ref}
    >
      <ErrorBoundary
        fallback={
          <h2>
            {intl.formatMessage({
              defaultMessage: "Unable to display map",
            })}
          </h2>
        }
      >
        <Map {...mapOptions}>{children}</Map>
      </ErrorBoundary>
      <div className={styles.ctaButtons}>
        {onClose && (
          <Button
            theme="base"
            intent="inverted"
            variant="icon"
            size="small"
            className={styles.closeButton}
            onClick={onClose}
          >
            <MaterialIcon icon="close" color="CurrentColor" />
            <span>
              {intl.formatMessage({
                defaultMessage: "Close the map",
              })}
            </span>
          </Button>
        )}
        <div className={styles.zoomButtons}>
          <Button
            theme="base"
            intent="inverted"
            variant="icon"
            size="small"
            className={styles.zoomButton}
            onClick={zoomIn}
            aria-label={intl.formatMessage({
              defaultMessage: "Zoom out",
            })}
          >
            <MaterialIcon icon="add" color="CurrentColor" size={20} />
          </Button>
          <Button
            theme="base"
            intent="inverted"
            variant="icon"
            size="small"
            className={styles.zoomButton}
            onClick={zoomOut}
            aria-label={intl.formatMessage({
              defaultMessage: "Zoom in",
            })}
          >
            <MaterialIcon icon="remove" color="CurrentColor" size={20} />
          </Button>
        </div>
      </div>
    </div>
  )
}
