'use client'

import { AnimatePresence, motion } from 'motion/react'
import { type PropsWithChildren, useEffect, useState } from 'react'
import {
  Dialog,
  DialogTrigger,
  Modal as AriaModal,
  ModalOverlay,
} from 'react-aria-components'

import {
  type AnimationState,
  AnimationStateEnum,
  type InnerModalProps,
  type ModalProps,
} from './modal'
import { fade, slideInOut } from './motionVariants'

import styles from './modal.module.css'
import { Typography } from '../../Typography'
import { MaterialIcon } from '../../Icons/MaterialIcon'

const MotionOverlay = motion.create(ModalOverlay)
const MotionModal = motion.create(AriaModal)

function InnerModal({
  animation,
  onAnimationComplete = () => undefined,
  setAnimation,
  onToggle,
  isOpen,
  children,
  title,
  subtitle,
  hideHeader,
}: PropsWithChildren<InnerModalProps>) {
  function modalStateHandler(newAnimationState: AnimationState) {
    setAnimation((currentAnimationState) =>
      newAnimationState === AnimationStateEnum.hidden &&
      currentAnimationState === AnimationStateEnum.hidden
        ? AnimationStateEnum.unmounted
        : currentAnimationState
    )
    if (newAnimationState === AnimationStateEnum.visible) {
      onAnimationComplete()
    }
  }

  function onOpenChange(state: boolean) {
    onToggle!(state)
  }

  return (
    <MotionOverlay
      animate={animation}
      className={styles.overlay}
      initial={'hidden'}
      isDismissable
      isExiting={animation === AnimationStateEnum.hidden}
      onAnimationComplete={modalStateHandler}
      variants={fade}
      isOpen={isOpen}
      onOpenChange={onOpenChange}
    >
      <MotionModal
        className={styles.modal}
        variants={slideInOut}
        animate={animation}
        initial={'hidden'}
      >
        <Dialog className={styles.dialog}>
          {({ close }) => (
            <>
              {!hideHeader && (
                <header className={styles.header}>
                  <div>
                    {title && (
                      <Typography variant="Title/Subtitle/lg">
                        <p>{title}</p>
                      </Typography>
                    )}
                    {subtitle && (
                      <Typography variant="Body/Lead text">
                        <span>{subtitle}</span>
                      </Typography>
                    )}
                  </div>

                  <button
                    onClick={close}
                    type="button"
                    className={styles.close}
                  >
                    <MaterialIcon icon="close" color="Icon/Feedback/Neutral" />
                  </button>
                </header>
              )}

              <section className={styles.content}>{children}</section>
            </>
          )}
        </Dialog>
      </MotionModal>
    </MotionOverlay>
  )
}

export default function Modal({
  onAnimationComplete = () => undefined,
  trigger,
  isOpen,
  onToggle,
  title,
  subtitle,
  children,
  withActions = false,
  hideHeader = false,
}: PropsWithChildren<ModalProps>) {
  const [animation, setAnimation] = useState<AnimationState>(
    AnimationStateEnum.visible
  )

  useEffect(() => {
    if (typeof isOpen === 'boolean') {
      setAnimation(
        isOpen ? AnimationStateEnum.visible : AnimationStateEnum.hidden
      )
    }
    if (isOpen === undefined) {
      setAnimation(AnimationStateEnum.unmounted)
    }
  }, [isOpen])

  const shouldRender = isOpen || animation !== AnimationStateEnum.unmounted

  if (!trigger) {
    return (
      <InnerModal
        onAnimationComplete={onAnimationComplete}
        animation={animation}
        setAnimation={setAnimation}
        onToggle={onToggle}
        isOpen={isOpen}
        title={title}
        subtitle={subtitle}
        withActions={withActions}
        hideHeader={hideHeader}
      >
        {children}
      </InnerModal>
    )
  }

  return (
    <DialogTrigger
      onOpenChange={(isOpen) =>
        setAnimation(
          isOpen ? AnimationStateEnum.visible : AnimationStateEnum.hidden
        )
      }
    >
      {trigger}
      <AnimatePresence>
        {shouldRender && (
          <InnerModal
            onAnimationComplete={onAnimationComplete}
            animation={animation}
            setAnimation={setAnimation}
            title={title}
            subtitle={subtitle}
            withActions={withActions}
          >
            {children}
          </InnerModal>
        )}
      </AnimatePresence>
    </DialogTrigger>
  )
}
