import {
  useEffect,
  forwardRef,
  useImperativeHandle,
  ForwardRefExoticComponent,
  ReactNode,
  CSSProperties,
} from 'react'
import classNames from 'classnames'
import { Loading, LoadingProps } from '../loading/Loading'
import { Popup, PopupProps } from '../popup/Popup'
import { Icon } from '../icon/Icon'
import { useSetTimeout } from '../../use'
import './Toast.scss'

import {
  show,
  text,
  success,
  fail,
  loading,
  hide,
  ToastShowMethod,
  ToastShortcutMethod,
} from './ToastImperative'
import { CommonComponentProps } from '../../utils/types'

export interface ToastProps extends CommonComponentProps {
  className?: string
  style?: CSSProperties
  type?: 'text' | 'loading' | 'success' | 'fail' | 'custom'
  title?: ReactNode
  icon?: ReactNode
  loadingProps?: LoadingProps
  duration?: number
  onTimeout?: () => void
  visible?: boolean
  popupProps?: PopupProps
}

export interface Toast extends ForwardRefExoticComponent<ToastProps> {
  show: ToastShowMethod
  text: ToastShortcutMethod
  success: ToastShortcutMethod
  fail: ToastShortcutMethod
  loading: ToastShortcutMethod
  hide(): void
}

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

export const Toast = forwardRef<ToastImperativeHandle, ToastProps>(
  (props, ref) => {
    const {
      className,
      type = 'text',
      title,
      icon,
      loadingProps,
      duration = 1500,
      onTimeout,
      visible = false,
      popupProps = {},
      ...restProps
    } = props

    const {
      mask = false,
      placement = 'center-fade',
      lockScroll = false,
      ...restPopupProps
    } = popupProps

    const { reset, clear } = useSetTimeout(
      () => {
        onTimeout?.()
      },
      duration,
      () => type !== 'loading'
    )

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

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

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

    const toastClass = classNames(
      's-toast',
      {
        's-toast-text': type === 'text',
      },
      className
    )

    return (
      <Popup
        {...restPopupProps}
        visible={visible}
        placement={placement}
        lockScroll={lockScroll}
        mask={mask}
      >
        <div {...restProps} className={toastClass}>
          {type !== 'text' && (
            <div className="s-toast-icon">
              {icon ||
                (type === 'loading' ? (
                  <Loading {...loadingProps}></Loading>
                ) : (
                  <Icon prefix="si" name={type} size="1em"></Icon>
                ))}
            </div>
          )}
          <div className="s-toast-title">{title}</div>
        </div>
      </Popup>
    )
  }
) as Toast

Toast.show = show
Toast.text = text
Toast.success = success
Toast.fail = fail
Toast.loading = loading
Toast.hide = hide

export default Toast
