import { Modal, Slider } from 'antd'
import LocaleReceiver from 'antd/lib/locale-provider/LocaleReceiver'
import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint'
// import ImageBlobReduce from "image-blob-reduce";
import Loading from 'components/Loading'
import React, {
  forwardRef,
  useCallback,
  useMemo,
  useRef,
  useState
} from 'react'
import './index.less'

const pkg = 'antd-img-re-zoom'
const noop = () => {
  console.log('')
}

const ZOOM_STEP = 5

const ImgReZoom = (props: ImgReZoomProps) => {
  const {
    minZoom = 50,
    maxZoom = 100,
    resizeMaxSize,
    modalTitle,
    modalWidth,
    modalOk,
    modalCancel,
    beforeCrop,
    children,
    onSetImageWidth
  } = props

  const [src, setSrc] = useState('')
  const [zoomVal, setZoomVal] = useState(maxZoom)
  const [loading, setLoading] = useState(false)
  const [file, setFile] = useState()

  const beforeUploadRef: any = useRef()
  const fileRef: any = useRef()
  const resolveRef: any = useRef(noop)
  const rejectRef: any = useRef(noop)
  const screens = useBreakpoint()
  /**
   * Upload
   */
  const renderUpload = useCallback(() => {
    const upload = Array.isArray(children) ? children[0] : children
    const { beforeUpload, accept, ...restUploadProps } = upload.props
    beforeUploadRef.current = beforeUpload

    return {
      ...upload,
      props: {
        ...restUploadProps,
        accept: accept || 'image/png,image/jpeg,image/webp',
        beforeUpload: (file: any, fileList: any) =>
          new Promise(async (resolve, reject) => {
            const isValid = beforeCrop ? await beforeCrop(file, fileList) : true
            if (!isValid) {
              reject()
              return
            }
            setFile(file)
            fileRef.current = file
            resolveRef.current = resolve
            rejectRef.current = reject
            const reader = new FileReader()
            reader.addEventListener('load', () => {
              setLoading(false)
              setSrc(reader.result as string)
            })
            reader.readAsDataURL(file)
          })
      }
    }
  }, [beforeCrop, resizeMaxSize, children])

  /**
   * Controls
   */
  const isMinZoom = zoomVal - ZOOM_STEP < minZoom
  const isMaxZoom = zoomVal + ZOOM_STEP > maxZoom
  const subZoomVal = useCallback(() => {
    if (!isMinZoom) setZoomVal(zoomVal - ZOOM_STEP)
  }, [isMinZoom, zoomVal])

  const addZoomVal = useCallback(() => {
    if (!isMaxZoom) setZoomVal(zoomVal + ZOOM_STEP)
  }, [isMaxZoom, zoomVal])

  const modalProps = useMemo(() => {
    const obj: any = {
      width: modalWidth,
      okText: modalOk,
      cancelText: modalCancel
    }
    Object.keys(obj).forEach(key => {
      if (!obj[key]) delete obj[key]
    })
    return obj
  }, [modalCancel, modalOk, modalWidth])

  const onClose = useCallback(() => {
    setSrc('')
    setFile(undefined)
    setZoomVal(maxZoom)
  }, [])

  const onOk = useCallback(async () => {
    onClose()
    onSetImageWidth?.(`${zoomVal}%`)
    if (typeof beforeUploadRef.current !== 'function')
      return resolveRef.current(file)

    const res = beforeUploadRef.current(file, [file])

    if (typeof res !== 'boolean' && !res) {
      console.error('beforeUpload must return a boolean or Promise')
      return
    }

    if (res === true) return resolveRef.current(file)
    if (res === false) return rejectRef.current('not upload')
    let newFile = file
    if (res && typeof res.then === 'function') {
      try {
        const passedFile = await res
        const type = Object.prototype.toString.call(passedFile)
        if (type === '[object File]' || type === '[object Blob]')
          newFile = passedFile
        resolveRef.current(newFile)
      } catch (err) {
        rejectRef.current(err)
      }
    }
  }, [zoomVal, file])

  const renderComponent = (titleOfModal: string) => (
    <>
      {renderUpload()}
      {src ? (
        <Modal
          visible={true}
          wrapClassName={`${pkg}-modal`}
          title={titleOfModal}
          onOk={onOk}
          onCancel={onClose}
          maskClosable={false}
          destroyOnClose
          centered
          {...modalProps}
        >
          <div className={`${pkg}-container`}>
            <div className={`${pkg}-media-container`}>
              <img style={{ width: `${zoomVal}%` }} src={src} />
            </div>
          </div>

          <div className={`${pkg}-control zoom`}>
            <button onClick={subZoomVal} disabled={isMinZoom}>
              －
            </button>
            <Slider
              min={minZoom}
              max={maxZoom}
              step={ZOOM_STEP}
              value={zoomVal}
              onChange={setZoomVal}
              tipFormatter={value => `${value}%`}
            />
            <button onClick={addZoomVal} disabled={isMaxZoom}>
              ＋
            </button>
          </div>
        </Modal>
      ) : loading && screens['xs'] ? (
        <Loading />
      ) : (
        <></>
      )}
    </>
  )

  if (modalTitle) return renderComponent(modalTitle)

  return (
    <LocaleReceiver>
      {(locale, localeCode) =>
        renderComponent(localeCode === 'zh-cn' ? '编辑图片' : 'Edit image')
      }
    </LocaleReceiver>
  )
}

interface ImgReZoomProps {
  shape?: 'rect' | 'round'
  grid?: boolean
  rotate?: boolean
  minZoom?: number
  maxZoom?: number
  fillColor?: string
  resizeMaxSize?: number
  modalTitle?: string
  modalWidth?: number | string
  modalOk?: string
  modalCancel?: string
  beforeCrop?: any
  cropperProps?: any
  children?: any
  onSetImageWidth?: (value: string) => void
}

export default forwardRef(ImgReZoom)
