import {
  CSSProperties,
  ReactNode,
  useEffect,
  forwardRef,
  useImperativeHandle,
  ForwardRefExoticComponent,
  ForwardedRef,
} from 'react'
import classNames from 'classnames'
import { Popup, PopupProps } from '../popup/Popup'
import { useSetTimeout } from '../../use'
import './Notify.scss'

import {
  show,
  info,
  success,
  warning,
  error,
  hide,
  NotifyShowMethod,
  NotifyShortcutMethod,
} from './NotifyImperative'
import { CommonComponentProps } from '../../utils/types'

export interface NotifyProps extends CommonComponentProps {
  className?: string
  style?: CSSProperties
  children?: ReactNode
  type?: 'info' | 'success' | 'warning' | 'error'
  message?: ReactNode
  duration?: number
  color?: string
  background?: string
  onTimeout?: () => any
  visible?: boolean
  popupProps?: PopupProps
}

export interface Notify extends ForwardRefExoticComponent<NotifyProps> {
  show: NotifyShowMethod
  info: NotifyShortcutMethod
  success: NotifyShortcutMethod
  warning: NotifyShortcutMethod
  error: NotifyShortcutMethod
  hide(): void
}

export interface NotifyImperative {
  clear: () => void
  reset: () => void
}

export const Notify = forwardRef<NotifyImperative, NotifyProps>(
  (props, ref) => {
    const {
      className,
      style,
      children,
      type = 'info',
      message,
      duration = 3000,
      color,
      background,
      onTimeout,
      visible = false,
      popupProps = {},
      ...restProps
    } = props

    const {
      mask = false,
      placement = 'top',
      lockScroll = false,
      ...restPopupProps
    } = popupProps

    const { reset, clear } = useSetTimeout(() => {
      onTimeout?.()
    }, duration)

    useEffect(() => {
      if (visible) {
        reset()
      } else {
        clear()
      }
    }, [visible])

    useEffect(() => {
      reset()
    }, [duration])

    useImperativeHandle(ref, () => ({
      reset,
      clear,
    }))

    const notifyClass = classNames('s-notify', 's-notify-' + type, className)
    const notifyStyle = {
      color,
      background,
      ...style,
    }

    return (
      <Popup
        {...restPopupProps}
        mask={mask}
        visible={visible}
        placement={placement}
        lockScroll={lockScroll}
      >
        <div {...restProps} className={notifyClass} style={notifyStyle}>
          {message}
        </div>
      </Popup>
    )
  }
) as Notify

Notify.show = show
Notify.info = info
Notify.success = success
Notify.warning = warning
Notify.error = error
Notify.hide = hide

export default Notify
