import { FocusModal, clx } from "@medusajs/ui"
import { ComponentType, PropsWithChildren, useEffect, useState } from "react"
import { Path, useNavigate } from "react-router-dom"
import { useStateAwareTo } from "../hooks/use-state-aware-to"
import { RouteModalForm } from "../route-modal-form"
import { useRouteModal } from "../route-modal-provider"
import { RouteModalProvider } from "../route-modal-provider/route-provider"
import { StackedModalProvider } from "../stacked-modal-provider"

type RouteFocusModalProps = PropsWithChildren<{
  prev?: string | Partial<Path> | number
}>

const Root: ComponentType<RouteFocusModalProps> = ({ prev = "..", children }: RouteFocusModalProps) => {
  const navigate = useNavigate()
  const [open, setOpen] = useState(false)
  const [stackedModalOpen, onStackedModalOpen] = useState(false)

  const to: string | Partial<Path> | number =
    typeof prev === "number" ? prev : useStateAwareTo(prev)

  /**
   * Open the modal when the component mounts. This
   * ensures that the entry animation is played.
   */
  useEffect(() => {
    setOpen(true)

    return () => {
      setOpen(false)
      onStackedModalOpen(false)
    }
  }, [])

  const handleOpenChange = (open: boolean) => {
    if (!open) {
      document.body.style.pointerEvents = "auto"
      if (typeof to === "number") {
        navigate(to)
      } else {
        navigate(to, { replace: true })
      }
      return
    }

    setOpen(open)
  }

  return (
    <FocusModal open={open} onOpenChange={handleOpenChange}>
      <RouteModalProvider prev={to}>
        <StackedModalProvider onOpenChange={onStackedModalOpen}>
          <Content stackedModalOpen={stackedModalOpen}>{children}</Content>
        </StackedModalProvider>
      </RouteModalProvider>
    </FocusModal>
  )
}

type ContentProps = PropsWithChildren<{
  stackedModalOpen: boolean
}>

const Content: ComponentType<ContentProps> = ({ stackedModalOpen, children }: ContentProps) => {
  const { __internal } = useRouteModal()

  const shouldPreventClose = !__internal.closeOnEscape

  return (
    <FocusModal.Content
      onEscapeKeyDown={
        shouldPreventClose
          ? (e) => {
              e.preventDefault()
            }
          : undefined
      }
      className={clx({
        "!bg-ui-bg-disabled !inset-x-5 !inset-y-3": stackedModalOpen,
      })}
    >
      <FocusModal.Title className="sr-only" />
      {children}
    </FocusModal.Content>
  )
}

const Header: typeof FocusModal.Header = FocusModal.Header
const Title: typeof FocusModal.Title = FocusModal.Title
const Description: typeof FocusModal.Description = FocusModal.Description
const Footer: typeof FocusModal.Footer = FocusModal.Footer
const Body: typeof FocusModal.Body = FocusModal.Body
const Close: typeof FocusModal.Close = FocusModal.Close
const Form: typeof RouteModalForm = RouteModalForm

/**
 * FocusModal that is used to render a form on a separate route.
 *
 * Typically used for forms creating a resource or forms that require
 * a lot of space.
 */
export const RouteFocusModal: typeof Root & {
  Header: typeof FocusModal.Header;
  Title: typeof FocusModal.Title;
  Body: typeof FocusModal.Body;
  Description: typeof FocusModal.Description;
  Footer: typeof FocusModal.Footer;
  Close: typeof FocusModal.Close;
  Form: typeof RouteModalForm;
} = Object.assign(Root, {
  Header,
  Title,
  Body,
  Description,
  Footer,
  Close,
  Form,
})
