'use client'

import { useCallback, useContext, useRef } from 'react'
import { Dialog, Modal, ModalOverlay } from 'react-aria-components'
import { IconButton } from '../IconButton'
import { Typography } from '../Typography'

import { SidePeekContext } from './SidePeekContext'

import SidePeekSEO from './SidePeekSEO'

import { debounce } from '@scandic-hotels/common/utils/debounce'
import { KeepBodyVisible } from './KeepBodyVisible'
import styles from './sidePeek.module.css'

interface SidePeekProps {
  contentKey?: string
  title: string
  isOpen?: boolean
  openInRoot?: boolean
  handleClose?: (isOpen: boolean) => void
  closeLabel: string
  shouldInert?: boolean
}

export default function SidePeek({
  children,
  title,
  contentKey,
  handleClose,
  isOpen,
  openInRoot = false,
  closeLabel,
  shouldInert,
}: React.PropsWithChildren<SidePeekProps>) {
  const rootDiv = useRef<HTMLDivElement>(null)
  const headerRef = useRef<HTMLElement>(null)
  const dialogRef = useRef<HTMLDivElement>(null)

  const context = useContext(SidePeekContext)

  const updateHeightRefCallback = useCallback((node: HTMLElement | null) => {
    if (node) {
      const debouncedUpdate = debounce(([entry]: ResizeObserverEntry[]) => {
        const height = entry.contentRect.height

        dialogRef.current?.style.setProperty(
          '--sidepeek-header-height',
          `${height}px`
        )
      }, 100)

      const observer = new ResizeObserver(debouncedUpdate)
      observer.observe(node)

      return () => {
        observer.unobserve(node)
        observer.disconnect()
        dialogRef.current?.style.removeProperty('--sidepeek-header-height')
      }
    }
  }, [])

  function onClose() {
    const closeHandler = handleClose || context?.handleClose
    closeHandler?.(false)
  }

  return (
    <>
      <div ref={openInRoot ? null : rootDiv}>
        <ModalOverlay
          UNSTABLE_portalContainer={rootDiv.current || undefined}
          className={styles.overlay}
          isOpen={
            isOpen || (!!contentKey && contentKey === context?.activeSidePeek)
          }
          onOpenChange={onClose}
          isDismissable
        >
          <Modal className={styles.modal}>
            <Dialog
              ref={dialogRef}
              className={styles.dialog}
              aria-label={title}
            >
              <aside className={styles.aside}>
                <header
                  ref={(node) => {
                    headerRef.current = node
                    return updateHeightRefCallback(node)
                  }}
                  className={styles.header}
                >
                  <div className={styles.headerContent}>
                    {title ? (
                      <Typography variant="Title/md">
                        <h2 className={styles.heading}>{title}</h2>
                      </Typography>
                    ) : null}
                    <IconButton
                      variant="Muted"
                      emphasis
                      aria-label={closeLabel}
                      onPress={onClose}
                      iconName="close"
                    />
                  </div>
                </header>
                <div className={styles.sidePeekContent}>{children}</div>
                <KeepBodyVisible />
              </aside>
            </Dialog>
          </Modal>
        </ModalOverlay>
      </div>

      <SidePeekSEO title={title} shouldInert={shouldInert}>
        {children}
      </SidePeekSEO>
    </>
  )
}
