import { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react'
import { CSSTransition } from 'react-transition-group'
import classNames from 'classnames'
import { reqCheck, reqGet } from '../../api/index'
import { aesEncrypt } from '../../utils/ase'
import { resetSize } from '../../utils/util'
import { useVerifyContext } from '@/pages/sys/login/providers/VerifyProvider'
import { ReloadOutlined } from '@ant-design/icons'
import { SvgIcon } from '@/components/icon'
import { VerifySlideWrapper } from './style'

export interface VerifySlideRef {
  refresh: () => void
}

interface VerifySlideProps {
  mode?: string
  captchaType: string
  type?: string
  vSpace?: number
  explain?: string
  barSize?: Record<string, string>
  blockSize?: Record<string, string>
  setClickShowFn?: (val: boolean) => any
  closeBoxFn?: () => any
  imgSize?: Record<string, string>
}

const VerifySlide = memo(
  forwardRef<VerifySlideRef, VerifySlideProps>(
    (
      {
        mode = 'fixed',
        captchaType,
        type = '1',
        vSpace = 5,
        explain = '拖动箭头填充拼图',
        barSize = { width: '310px', height: '40px' },
        blockSize = { width: '50px', height: '50px' },
        setClickShowFn,
        closeBoxFn,
        imgSize = { width: '310px', height: '155px' }
      },
      ref
    ) => {
      const props = {
        mode,
        captchaType,
        type,
        vSpace,
        explain,
        barSize,
        blockSize,
        setClickShowFn,
        closeBoxFn,
        imgSize
      }
      useImperativeHandle(ref, () => {
        return { refresh }
      })
      const vmRef = useRef<HTMLDivElement>(null)
      if (vmRef.current) vmRef.current.onselectstart = () => false
      const barAreaRef = useRef<HTMLDivElement>(null)
      const [setSize, setSetSize] = useState({
        imgHeight: 0,
        imgWidth: 0,
        barHeight: 0,
        barWidth: 0
      })
      const [secretKey, setSecretKey] = useState('') // 后端返回的加密秘钥
      const [passFlag, setPassFlag] = useState<boolean>() // 是否通过的标识
      const [backImgBase, setbackImgBase] = useState('') // 验证码背景图片
      const [blockBackImgBase, setBlockBackImgBase] = useState('') // 验证滑块的背景图片
      const [backToken, setBackToken] = useState('') // 后端返回的唯一token值
      const [startMoveTime, setStartMoveTime] = useState<number>() // 移动开始的时间
      const [endMovetime, setEndMovetime] = useState<number>() // 移动结束的时间
      const [tipWords, setTipWords] = useState('')
      const [text, setText] = useState('')
      const [finishText, setFinishText] = useState('')
      const [moveBlockLeft, setMoveBlockLeft] = useState<string | undefined>(undefined)
      const [leftBarWidth, setLeftBarWidth] = useState<string | number | undefined>(undefined)
      // 移动中样式
      // const [moveBlockBackgroundColor, setMoveBlockBackgroundColor] = useState<string | undefined>(
      //   undefined
      // )
      const [leftBarBorderColor, setLeftBarBorderColor] = useState('#ddd')
      // const [iconColor, setIconColor] = useState<string | undefined>(undefined)
      const [iconClass, setIconClass] = useState('icon-right')
      const [status, setStatus] = useState(false) // 鼠标状态
      const [isEnd, setIsEnd] = useState(false)
      const [showRefresh, setShowRefresh] = useState(true) // 显示刷新按钮
      const [transitionLeft, setTransitionLeft] = useState('')
      const [transitionWidth, setTransitionWidth] = useState('')
      const [startLeft, setStartLeft] = useState(0)
      // 刷新
      const refresh = () => {
        setShowRefresh(true)
        setFinishText('')

        setTransitionLeft('left .3s')
        setMoveBlockLeft('0px')

        setLeftBarWidth(undefined)
        setTransitionWidth('width .3s')

        setLeftBarBorderColor('#ddd')
        // setMoveBlockBackgroundColor('#fff')
        // setIconColor('#000')
        setIconClass('icon-right')
        setIsEnd(false)

        getPictrue()
        setTimeout(() => {
          setTransitionWidth('')
          setTransitionLeft('')
          setText(props.explain)
        }, 300)
      }
      // 请求背景图片和验证图片
      const getPictrue = () => {
        // const data = {
        //   captchaType: props.captchaType
        // }
        reqGet().then((response) => {
          const res = response.data
          if (res.repCode == '0000') {
            setbackImgBase(res.repData.originalImageBase64)
            setBlockBackImgBase(res.repData.jigsawImageBase64)
            setBackToken(res.repData.token)
            setSecretKey(res.repData.secretKey)
          } else {
            setTipWords(res.repMsg)
          }
        })
      }
      const resetSizeFn = resetSize
      // 鼠标按下
      const start = (e: any) => {
        e = e || window.event
        if (!e.touches) {
          // 兼容PC端
          var x = e.clientX
        } else {
          // 兼容移动端
          var x = e.touches[0].pageX
        }
        setStartLeft(Math.floor(x - barAreaRef.current!.getBoundingClientRect().left))
        setStartMoveTime(+new Date()) // 开始滑动的时间
        if (isEnd == false) {
          setText('')
          // setMoveBlockBackgroundColor('#1a1a1a')
          setLeftBarBorderColor('#1a1a1a')
          // setIconColor('#fff')
          e.stopPropagation()
          setStatus(true)
        }
      }
      // 使用ref保存状态, 使事件处理函数move & end中能使用最新值
      const statusRef = useRef(status)
      const isEndRef = useRef(isEnd)
      const startLeftRef = useRef(startLeft)
      const moveBlockLeftRef = useRef(moveBlockLeft)
      const startMoveTimeRef = useRef(startMoveTime)
      const endMovetimeRef = useRef(endMovetime)
      const secretKeyRef = useRef(secretKey)
      const backTokenRef = useRef(backToken)
      const setSizeRef = useRef(setSize)
      useEffect(() => {
        statusRef.current = status
      }, [status])
      useEffect(() => {
        isEndRef.current = isEnd
      }, [isEnd])
      useEffect(() => {
        startLeftRef.current = startLeft
      }, [startLeft])
      useEffect(() => {
        moveBlockLeftRef.current = moveBlockLeft
      }, [moveBlockLeft])
      useEffect(() => {
        startMoveTimeRef.current = startMoveTime
      }, [startMoveTime])
      useEffect(() => {
        endMovetimeRef.current = endMovetime
      }, [endMovetime])
      useEffect(() => {
        secretKeyRef.current = secretKey
      }, [secretKey])
      useEffect(() => {
        backTokenRef.current = backToken
      }, [backToken])
      useEffect(() => {
        setSizeRef.current = setSize
      }, [setSize])
      // 鼠标移动
      const move = (e: TouchEvent | MouseEvent) => {
        e = e || window.event
        if (statusRef.current && isEndRef.current == false) {
          if (!(e as TouchEvent).touches) {
            // 兼容PC端
            var x = (e as MouseEvent).clientX
          } else {
            // 兼容移动端
            var x = (e as TouchEvent).touches[0].pageX
          }
          var bar_area_left = barAreaRef.current!.getBoundingClientRect().left
          var move_block_left = x - bar_area_left // 小方块相对于父元素的left值
          if (
            move_block_left >=
            barAreaRef.current!.offsetWidth - parseInt(parseInt(props.blockSize.width) / 2) - 2
          ) {
            move_block_left =
              barAreaRef.current!.offsetWidth - parseInt(parseInt(props.blockSize.width) / 2) - 2
          }
          if (move_block_left <= 0) {
            move_block_left = parseInt(parseInt(props.blockSize.width) / 2)
          }
          // 拖动后小方块的left值
          setMoveBlockLeft(move_block_left - startLeftRef.current + 'px')
          setLeftBarWidth(move_block_left - startLeftRef.current + 'px')
        }
      }
      const { success, error } = useVerifyContext()
      // 鼠标松开
      const end = () => {
        setEndMovetime(+new Date())
        // 判断是否重合
        if (statusRef.current && isEndRef.current == false) {
          var moveLeftDistance = parseInt((moveBlockLeftRef.current || '').replace('px', ''))
          moveLeftDistance = (moveLeftDistance * 310) / parseInt(setSizeRef.current.imgWidth)
          const data = {
            captchaType: props.captchaType,
            pointJson: secretKeyRef.current
              ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKeyRef.current)
              : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
            token: backTokenRef.current
          }
          reqCheck(data).then((response) => {
            const res = response.data
            if (res?.repCode == '0000') {
              // setMoveBlockBackgroundColor('#5cb85c')
              setLeftBarBorderColor('#5cb85c')
              // setIconColor('#fff')
              setIconClass('icon-check')
              setShowRefresh(false)
              setIsEnd(true)
              if (props.mode === 'pop') {
                setTimeout(() => {
                  if (props.setClickShowFn) {
                    props.setClickShowFn(false)
                  }
                  refresh()
                }, 1500)
              }
              setPassFlag(true)
              setTipWords(
                `${((endMovetimeRef.current! - startMoveTimeRef.current!) / 1000).toFixed(
                  2
                )}s验证成功`
              )
              var captchaVerification = secretKeyRef.current
                ? aesEncrypt(
                    backTokenRef.current + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
                    secretKeyRef.current
                  )
                : backTokenRef.current + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 })
              setTimeout(() => {
                setTipWords('')
                if (props.closeBoxFn) {
                  props.closeBoxFn()
                }
                success({ captchaVerification })
              }, 1000)
            } else {
              // setMoveBlockBackgroundColor('#d9534f')
              setLeftBarBorderColor('#d9534f')
              // setIconColor('#fff')
              setIconClass('icon-close')
              setPassFlag(false)
              setTimeout(function () {
                refresh()
              }, 1000)
              if (error) {
                error(vmRef.current)
              }
              setTipWords('验证失败')
              setTimeout(() => {
                setTipWords('')
              }, 1000)
            }
          })
          setStatus(false)
        }
      }
      const init = () => {
        setText(props.explain)
        getPictrue()
        const setSizeVal = resetSizeFn(vmRef.current, props) // 重新设置宽度高度
        for (const key in setSizeVal) {
          setSetSize((setSize) => ({
            ...setSize,
            [key]: setSizeVal[key as keyof typeof setSize]
          }))
        }

        window.removeEventListener('touchmove', (e) => {
          move(e)
        })
        window.removeEventListener('mousemove', (e) => {
          move(e)
        })

        // 鼠标松开
        window.removeEventListener('touchend', () => {
          end()
        })
        window.removeEventListener('mouseup', () => {
          end()
        })

        window.addEventListener('touchmove', (e) => {
          move(e)
        })
        window.addEventListener('mousemove', (e) => {
          move(e)
        })

        // 鼠标松开
        window.addEventListener('touchend', () => {
          end()
        })
        window.addEventListener('mouseup', () => {
          end()
        })
      }
      // type变化则全面刷新
      useEffect(() => {
        init()
      }, [props.type])
      return (
        <VerifySlideWrapper ref={vmRef} style={{ position: 'relative' }}>
          {props.type === '2' && (
            <div
              className='verify-img-out rounded-[14px] overflow-hidden'
              style={{
                height: parseInt(setSize.imgHeight) + props.vSpace + 'px'
              }}>
              <div
                className='verify-img-panel'
                style={{ width: setSize.imgWidth, height: setSize.imgHeight }}>
                <img
                  src={'data:image/png;base64,' + backImgBase}
                  alt=''
                  style={{ width: '100%', height: '100%', display: 'block' }}
                />
                <div
                  style={{ display: showRefresh ? 'block' : 'none' }}
                  className='verify-refresh'
                  onClick={refresh}>
                  <ReloadOutlined className='icon-refresh' />
                </div>
                <CSSTransition
                  in={!!tipWords}
                  unmountOnExit={true}
                  classNames='tips'
                  timeout={500}
                  appear>
                  <span
                    className={classNames('verify-tips', {
                      'suc-bg': passFlag,
                      'err-bg': !passFlag
                    })}>
                    {tipWords}
                  </span>
                </CSSTransition>
              </div>
            </div>
          )}
          {/* 公共部分 */}
          <div
            ref={barAreaRef}
            className='verify-bar-area'
            style={{
              width: setSize.imgWidth,
              height: props.barSize.height,
              lineHeight: props.barSize.height,
              borderRadius: barSize.height
            }}>
            <span className='verify-msg'>{text}</span>
            <div
              className='verify-left-bar'
              style={{
                width:
                  leftBarWidth !== undefined
                    ? parseFloat((leftBarWidth as string).slice(0, -2)) +
                      parseFloat(barSize.height.slice(0, -2)) +
                      'px'
                    : props.barSize.height,
                height: props.barSize.height,
                borderColor: leftBarBorderColor,
                borderRadius: barSize.height,
                transition: transitionWidth
              }}>
              <span className='verify-msg'>{finishText}</span>
              <div
                className='verify-move-block'
                style={{
                  width: props.barSize.height,
                  height: props.barSize.height,
                  left: moveBlockLeft,
                  transition: transitionLeft,
                  borderRadius: barSize.height
                }}
                onTouchStart={start}
                onMouseDown={start}>
                {iconClass === 'icon-right' && (
                  <SvgIcon icon='yanzhenghuakuai' className='!w-full !h-full' />
                )}
                {iconClass === 'icon-close' && (
                  <SvgIcon icon='yanzhengshibai' className='!w-full !h-full' />
                )}
                {iconClass === 'icon-check' && (
                  <SvgIcon icon='yanzhengchenggong' className='!w-full !h-full' />
                )}
                {props.type === '2' && (
                  <div
                    className='verify-sub-block'
                    style={{
                      width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
                      height: setSize.imgHeight,
                      top: '-' + (parseInt(setSize.imgHeight) + props.vSpace + 10) + 'px',
                      backgroundSize: setSize.imgWidth + ' ' + setSize.imgHeight
                    }}>
                    <img
                      src={'data:image/png;base64,' + blockBackImgBase}
                      alt=''
                      style={{ width: '100%', height: '100%', display: 'block' }}
                    />
                  </div>
                )}
              </div>
            </div>
          </div>
        </VerifySlideWrapper>
      )
    }
  )
)

export default VerifySlide
