"use client"

import { useCallback, useEffect, useRef, useState } from "react"

import { debounce } from "@/utils/debounce"

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

export function MapContainer({ children }: { children: React.ReactNode }) {
  const [mapHeight, setMapHeight] = useState("")
  const [mapTop, setMapTop] = useState("")
  const [mapZIndex, setMapZIndex] = useState(0)
  const [scrollHeightWhenOpened, setScrollHeightWhenOpened] = useState(0)

  const rootDiv = useRef<HTMLDivElement | null>(null)

  // Calculate the height of the map based on the viewport height from the start-point (below the header and booking widget)
  const handleMapHeight = useCallback(() => {
    const topPosition = rootDiv.current?.getBoundingClientRect().top ?? 0
    const scrollY = window.scrollY
    setMapHeight(`calc(100dvh - ${topPosition + scrollY}px)`)
    setMapTop(`${topPosition + scrollY}px`)
    setMapZIndex(11)
  }, [])

  useEffect(() => {
    const originalOverflowY = document.body.style.overflowY

    // Function to enforce overflowY to hidden
    const enforceOverflowHidden = () => {
      if (document.body.style.overflowY !== "hidden") {
        document.body.style.overflowY = "hidden"
      }
    }

    // Set overflowY to hidden initially
    enforceOverflowHidden()

    // Create a MutationObserver to watch for changes to the style attribute
    const observer = new MutationObserver(() => {
      enforceOverflowHidden()
    })

    // Observe changes to the style attribute of the body
    observer.observe(document.body, {
      attributes: true,
      attributeFilter: ["style"],
    })

    return () => {
      // Disconnect the observer on cleanup
      observer.disconnect()
      // Restore the original overflowY style
      document.body.style.overflowY = originalOverflowY
    }
  }, [])

  // Making sure the map is always opened at the top of the page,
  // just below the header and booking widget as these should stay visible.
  // When closing, the page should scroll back to the position it was before opening the map.
  useEffect(() => {
    // Skip the first render
    if (!rootDiv.current) {
      return
    }

    if (scrollHeightWhenOpened === 0) {
      const scrollY = window.scrollY
      setScrollHeightWhenOpened(scrollY)
      window.scrollTo({ top: 0, behavior: "instant" })
    }
  }, [scrollHeightWhenOpened, rootDiv])

  useEffect(() => {
    const debouncedResizeHandler = debounce(function () {
      handleMapHeight()
    })

    const observer = new ResizeObserver(debouncedResizeHandler)

    observer.observe(document.documentElement)

    return () => {
      if (observer) {
        observer.unobserve(document.documentElement)
      }
    }
  }, [rootDiv, handleMapHeight])

  return (
    <div className={styles.wrapper} ref={rootDiv}>
      <div
        style={
          {
            "--hotel-map-height": mapHeight,
            "--hotel-map-top": mapTop,
            "--hotel-dynamic-map-z-index": mapZIndex,
          } as React.CSSProperties
        }
        className={styles.dynamicMap}
      >
        {children}
      </div>
    </div>
  )
}
