import { className } from 'lib/css'
import { FC } from 'preact/compat'
import { MutableRef, useCallback, useEffect } from 'preact/hooks'
import Icon from 'ui/components/layout/icon'
import {
  useGeneratedId,
  useOptionButton,
  useSeamlyOptions,
} from 'ui/hooks/seamly-hooks'
import useClickOutside from 'ui/hooks/use-click-outside'
import { focusElement } from 'ui/utils/general-utils'

export type FramePosition = {
  vertical: 'top' | 'bottom'
  horizontal: 'left' | 'right'
}

type OptionsFrameProps = {
  className?: string
  onCancel?: () => void
  headingText: string
  description?: string
  descriptionId?: string
  cancelButtonText?: string
  cancelButtonRef?: MutableRef<HTMLButtonElement | null>
  disableButtonFocusing?: boolean
  position: FramePosition
}

const OptionsFrame: FC<OptionsFrameProps> = ({
  className: givenClassName,
  children,
  onCancel,
  headingText,
  description,
  descriptionId,
  cancelButtonText,
  cancelButtonRef,
  disableButtonFocusing,
  position = {
    horizontal: 'left',
    vertical: 'top',
  },
}) => {
  const mainHeadingId = useGeneratedId()
  // @todo Lift this from the "options frame" into something reusable
  // when you're not using options
  const { hideOption } = useSeamlyOptions()
  const { focusButton } = useOptionButton()

  const closePanel = useCallback(() => {
    hideOption()
    if (!disableButtonFocusing) {
      focusButton()
    }
  }, [disableButtonFocusing, focusButton, hideOption])

  const onCancelHandler = useCallback(() => {
    if (onCancel) {
      onCancel()
    }
    closePanel()
  }, [closePanel, onCancel])

  const container = useClickOutside(onCancelHandler)

  useEffect(() => {
    focusElement(container.current)
  }, [container])

  return (
    <section
      className={className(
        'options',
        {
          'options--right': position.horizontal === 'right',
          'options--left': position.horizontal === 'left',
          'options--top': position.vertical === 'top',
          'options--bottom': position.vertical === 'bottom',
        },
        givenClassName || '',
      )}
      aria-labelledby={mainHeadingId}
      tabIndex={-1}
      ref={container}
    >
      <div className={className('options__body')}>
        <h2 id={mainHeadingId} className={className('options__title')}>
          {headingText}
        </h2>
        <button
          type="button"
          onClick={onCancelHandler}
          aria-describedby={mainHeadingId}
          className={className('button', 'options__close')}
          ref={(btn) => {
            if (cancelButtonRef) {
              cancelButtonRef.current = btn
            }
          }}
        >
          <Icon name="close" size="16" alt="" />
          <span>{cancelButtonText}</span>
        </button>

        {description ? (
          <p className={className('options__description')} id={descriptionId}>
            {description}
          </p>
        ) : null}
        <div className={className('options__wrapper')}>{children}</div>
      </div>
    </section>
  )
}

export default OptionsFrame
