import React, { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'

import styles from './_modal.module.scss'
import Button from '../Button/Button'
import { type ConfirmationPopoverContentProps } from '../ConfirmationPopover/ConfirmationPopoverContent'
import FormFooter from '../Form/FormFooter'
import Icon from '../Icons/Icon'
import isClient from '../../services/isClient'
import { SideDrawer } from '../SideDrawer/SideDrawer'
import { type SideDrawerProps } from '../SideDrawer/SideDrawer'
import { useMediaQuery } from '../../hooks/responsiveHooks'
import BackgroundOverlay from '../BackgroundOverlay/BackgroundOverlay'
import { c } from '../../translations/LibraryTranslationService'

type BaseModalProps = Omit<SideDrawerProps, 'size'> & {
  size?: 'sm' | 'md' | 'lg' | 'xl'
  /** Optional z-index value for the modal container. Useful for controlling stacking order when multiple modals or overlays are present. Defaults to 9000. */
  zIndex?: number
}

type WithConfirmation = BaseModalProps & {
  /** Optionally hide the close icon in the header */
  hideCloseIcon?: never
  /** Optionally disable the outside click "close" functionality  */
  disableOutsideClick?: never
  /** The content to display in the confirmation popover */
  confirmation: Omit<ConfirmationPopoverContentProps, 'type'> & {
    close?: () => void
  }
  /** Optionally hide the header. Defaults to false */
  hideHeader?: never
}

type WithoutConfirmation = BaseModalProps & {
  confirmation?: never
  /** Optionally hide the close icon in the header */
  hideCloseIcon?: boolean
  /** Optionally disable the outside click "close" functionality  */
  disableOutsideClick?: boolean
  /** Optionally hide the header. Defaults to false */
  hideHeader?: boolean
}

export type ModalProps = WithConfirmation | WithoutConfirmation

const ConfirmationModal = ({
  header,
  body,
  cancelCallout,
  confirmCallout,
  confirmButtonText,
  cancelButtonText,
  type = 'black',
  close,
}: Omit<ConfirmationPopoverContentProps, 'type'> & {
  type?: 'red' | 'blue' | 'green' | 'black'
} & {
  close?: () => void
}): React.JSX.Element => {
  let buttonColor: 'primary' | 'primary-blue' = 'primary'
  switch (type) {
    // We want to use the primary blue button for green and blue. Eventually, we will have only one button color for "primary" and clean this up.
    case 'green':
    case 'blue':
      buttonColor = 'primary-blue'
      break
    default:
      break
  }

  return (
    <>
      <div className={styles.modalBody}>
        <div className={styles.modalHeader}>
          <div className={styles.modalHeaderContent}>{header}</div>
        </div>
        <div className={styles.modalContent}>{body}</div>
      </div>
      <div
        className={`${styles.modalFooterContent} ${styles.confirmationFooterContent}`}
      >
        <FormFooter
          {...(cancelCallout || close
            ? {
                cancelButtonProps: {
                  onClick: () => {
                    cancelCallout?.()
                    close?.()
                  },
                  children: cancelButtonText ?? c('cancel'),
                  styleType: 'secondary',
                },
              }
            : {})}
          saveButtonProps={{
            onClick: () => {
              confirmCallout()
              close?.()
            },
            children: confirmButtonText ?? c('confirm'),
            styleType: buttonColor,
            destructive: type === 'red',
          }}
        />
      </div>
    </>
  )
}

const Modal = (props: ModalProps): React.JSX.Element => {
  const {
    children,
    isOpen,
    closeCallout,
    headerContent,
    footerContent,
    hideCloseIcon = false,
    disableOutsideClick = false,
    confirmation,
    hideHeader = false,
    noContentPadding,
    size = 'md',
    fullWidth = false,
    qaTestId = 'modal',
    zIndex = 9000,
  } = props
  const isMobileView = useMediaQuery({ type: 'max', breakpoint: 'md' })
  const isMobileOpen = isMobileView && isOpen
  const isDesktopOpen = !isMobileView && isOpen
  const [isTransitioning, setIsTransitioning] = useState(false)
  const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined)

  const close = () => {
    setIsTransitioning(true)
    timeoutRef.current = setTimeout(() => {
      closeCallout()
      setIsTransitioning(false)
    }, 250)
  }

  const determineClose = () => {
    if (disableOutsideClick || confirmation) {
      return
    }
    close()
  }

  useEffect(() => {
    return () => {
      clearTimeout(timeoutRef.current)
    }
  }, [])

  const sideDrawerProps = {
    ...props,
    isOpen: isMobileOpen,
  } as SideDrawerProps

  return isClient ? (
    <>
      <SideDrawer {...sideDrawerProps} />
      {isDesktopOpen &&
        createPortal(
          <div
            className={styles.modalOuterContainer}
            style={{ zIndex: zIndex }}
          >
            <BackgroundOverlay
              close={determineClose}
              isTransitioning={isTransitioning}
              {...(disableOutsideClick || confirmation
                ? { style: { cursor: 'default' } }
                : {})}
            />
            <div
              className={`${styles.modalContainer} animated ${isTransitioning ? 'fadeOutDown' : 'slideInUp'} ${size ? styles[size] : ''} ${fullWidth ? styles.fullWidth : ''}`}
            >
              {confirmation ? (
                <ConfirmationModal {...confirmation} close={close} />
              ) : (
                <>
                  <div className={styles.modalBody}>
                    {!hideHeader && (
                      <div className={styles.modalHeader}>
                        <div className={styles.modalHeaderContent}>
                          {headerContent}
                        </div>
                        {!hideCloseIcon && (
                          <Button as='unstyled' onClick={close}>
                            <Icon
                              icon='x'
                              color='dark-purple'
                              qaTestId={`${qaTestId}-x-icon`}
                            />
                          </Button>
                        )}
                      </div>
                    )}
                    <div
                      className={`${styles.modalContent} ${noContentPadding ? styles.noPadding : ''}`}
                    >
                      {typeof children !== 'function' ? children : null}
                    </div>
                  </div>
                  {footerContent ? (
                    <div className={styles.modalFooterContent}>
                      {typeof footerContent === 'function'
                        ? footerContent({
                            close,
                          })
                        : footerContent}
                    </div>
                  ) : null}
                </>
              )}
            </div>
          </div>,
          document.body,
        )}
    </>
  ) : (
    <></>
  )
}

export default Modal
