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

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

const MEDIA_CLASS = `${pkg}-media`

// eslint-disable-next-line react/display-name
const EasyCrop = forwardRef((props: IEasyCropProps, ref) => {
  const {
    src,
    aspect,
    shape,
    grid,

    hasZoom,
    zoomVal,
    setZoomVal,

    minZoom,
    maxZoom,
    onComplete,

    cropperProps
  } = props
  const [crop, setCrop] = useState({ x: 0, y: 0 })
  const [cropSize, setCropSize] = useState({ width: 0, height: 0 })
  const imgSrc = useMemo(() => {
    const imgUrl = new URL(src)
    return `${imgUrl.origin}${imgUrl.pathname}`
  }, [src])
  const imgRef = useRef()

  // Get cropper params from imgkit Api or from querystring crp
  useEffect(() => {
    const srcObj = new URL(src)
    const urlCropperParams = new URLSearchParams(srcObj.search)?.get('crp')
    const urlCropParams = new URLSearchParams(srcObj.search)?.get('tr')
    let cropperParams = { x: 0, y: 0, zoomVal: 1 }
    const imgkitCropParams: any = {}

    if (urlCropParams) {
      try {
        const params = urlCropParams.split(',')
        params.map(pr => {
          const [key, value] = pr.split('-')
          imgkitCropParams[key] = value
        })
      } catch (e) {}
    }

    let coordinateFromMiddle = { x: 0, y: 0 }
    let zoom = 1
    if (urlCropperParams) {
      try {
        const { x, y, zoomVal } = JSON.parse(urlCropperParams)
        cropperParams = { x, y, zoomVal }
        coordinateFromMiddle = { x, y }
        zoom = zoomVal
      } catch (e) {}
    } else if (imgRef?.current && JSON.stringify(imgkitCropParams) != '{}') {
      const { naturalHeight, naturalWidth } = (imgRef.current as any).mediaSize
      const { width, height } = (imgRef.current as any).mediaSize
      const ratioWidth = height * aspect
      const widthZoomRatio = naturalWidth / imgkitCropParams.w
      const heightZoomRatio = naturalHeight / imgkitCropParams.h
      zoom = heightZoomRatio < widthZoomRatio ? heightZoomRatio : widthZoomRatio
      const axisZoomRatio = naturalHeight / (height * zoom)
      const imgHalfWidth = (width / 2) * zoom
      const imgHalfHeight = (height / 2) * zoom

      // cropFrame with zoom = 1
      const cropFrame = {
        width: width > ratioWidth ? ratioWidth : width,
        height: width > ratioWidth ? height : width / aspect
      }
      const cropFrameHalfWidth = cropFrame.width / 2
      const cropFrameHalfHeight = cropFrame.height / 2

      // Coordinate for imgageKit api
      const coordinateFromTopLeft = {
        x: imgkitCropParams.x ? imgkitCropParams.x / axisZoomRatio : 0,
        y: imgkitCropParams.y ? imgkitCropParams.y / axisZoomRatio : 0
      }

      // Coordinate for cropper
      coordinateFromMiddle = {
        x: imgHalfWidth - (coordinateFromTopLeft.x + cropFrameHalfWidth),
        y: imgHalfHeight - (coordinateFromTopLeft.y + cropFrameHalfHeight)
      }
    }

    setCrop(coordinateFromMiddle)
    setZoomVal(zoom > 1 ? zoom : 1)
  }, [src])

  const onCropComplete = (croppedArea: any, croppedAreaPixels: any) => {
    onComplete({ ...croppedAreaPixels, cropperParams: { ...crop, zoomVal } })
  }

  const onMediaLoaded = useCallback(
    mediaSize => {
      const { height, width } = mediaSize
      const ratioWidth = height * aspect

      if (width > ratioWidth) {
        setCropSize({ width: ratioWidth, height })
      } else {
        setCropSize({ width, height: width / aspect })
      }
    },
    [aspect]
  )

  const handleZoomChange = (zoom: number) => {
    setZoomVal(zoom < maxZoom ? zoom : maxZoom)
  }

  return (
    <Cropper
      {...cropperProps}
      ref={imgRef}
      image={imgSrc}
      crop={crop}
      cropSize={cropSize}
      onCropChange={setCrop}
      aspect={aspect}
      cropShape={shape}
      showGrid={grid}
      zoomWithScroll={hasZoom}
      zoom={zoomVal}
      onZoomChange={handleZoomChange}
      minZoom={minZoom}
      maxZoom={maxZoom}
      onCropComplete={onCropComplete}
      onMediaLoaded={onMediaLoaded}
      classes={{
        containerClassName: `${pkg}-container`,
        mediaClassName: MEDIA_CLASS
      }}
    />
  )
})

interface IEasyCropProps {
  src: string
  aspect: number
  shape: string
  grid: boolean
  hasZoom: boolean
  zoomVal: number
  setZoomVal: any
  rotateVal?: number
  setRotateVal?: any

  minZoom: number
  maxZoom: number
  onComplete: any
  cropperProps: any
}

const ImgCrop = (props: ImgCropProps, ref: any) => {
  const {
    src,
    aspect = 1,
    shape = 'rect',
    grid = false,
    quality = 0.4,

    zoom = true,
    minZoom = 1,
    resizeMaxSize,
    fillColor = 'white',

    modalTitle,
    modalWidth,
    modalOk,
    modalCancel,

    beforeCrop,
    children,

    cropperProps,
    handleCompletedCropUpdate,

    ...rest
  } = props

  const hasZoom = zoom === true

  const [loading, setLoading] = useState(false)
  const [isShowModal, setIsShowModal] = useState(false)
  const [zoomVal, setZoomVal] = useState(1)

  const [maxZoom, setMaxZoom] = useState(1)
  const [zoomStep, setZoomStep] = useState(0.1)
  const cropPixelsRef: any = useRef()
  const screens = useBreakpoint()

  useEffect(() => {
    const img = new Image()
    img.onload = () => {
      const { naturalHeight, naturalWidth } = img
      const maxHeighRatio = naturalHeight / 710
      const maxWidthRatio = naturalWidth / 564
      let calculatedMaxZoom =
        maxHeighRatio > maxWidthRatio ? maxWidthRatio : maxHeighRatio
      calculatedMaxZoom = calculatedMaxZoom > 1 ? calculatedMaxZoom : 1

      setMaxZoom(calculatedMaxZoom)
      setZoomStep((calculatedMaxZoom - 1) / 30)
    }
    img.src = src
  }, [src])

  /**
   * EasyCrop
   */
  const onComplete = useCallback(croppedAreaPixels => {
    cropPixelsRef.current = croppedAreaPixels
  }, [])

  /**
   * Controls
   */
  const isMinZoom = zoomVal <= minZoom
  const isMaxZoom = zoomVal >= maxZoom

  const subZoomVal = useCallback(() => {
    const zoom = zoomVal - zoomStep
    setZoomVal(zoom < minZoom ? minZoom : zoom)
  }, [isMinZoom, zoomVal, zoomStep])

  const addZoomVal = useCallback(() => {
    const zoom = zoomVal + zoomStep
    setZoomVal(zoom > maxZoom ? maxZoom : zoom)
  }, [isMaxZoom, zoomVal, zoomStep])

  /**
   * Modal
   */
  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 handleOnClick = () => {
    setIsShowModal(true)
  }

  const onClose = useCallback(() => {
    setIsShowModal(false)
    setZoomVal(1)
  }, [])

  const onOk = async () => {
    onClose()

    // Call function and pass param crop image for parent process
    handleCompletedCropUpdate({ cropParams: { ...cropPixelsRef.current } })
  }

  const renderComponent = (titleOfModal: string) => (
    <div data-testid="image-crop__update">
      <div
        className="overlay-update"
        onClick={handleOnClick}
        data-testid="image-crop__update-overlay"
      >
        <Text preset="semibold14">UPDATE</Text>
        <div className="opacity"></div>
      </div>

      {children}

      {isShowModal ? (
        <Modal
          visible={true}
          wrapClassName={`${pkg}-modal`}
          title={titleOfModal}
          onOk={onOk}
          onCancel={onClose}
          maskClosable={false}
          destroyOnClose
          centered
          data-testid="image-crop__update-modal"
          {...modalProps}
        >
          <EasyCrop
            ref={ref}
            src={src}
            aspect={aspect}
            shape={shape}
            grid={grid}
            hasZoom={hasZoom}
            zoomVal={zoomVal}
            setZoomVal={setZoomVal}
            minZoom={minZoom}
            maxZoom={maxZoom}
            onComplete={onComplete}
            cropperProps={cropperProps}
          />
          <div className={`${pkg}-control zoom`}>
            <button onClick={subZoomVal} disabled={isMinZoom}>
              －
            </button>
            <Slider
              tipFormatter={tip => tip?.toFixed(2)}
              min={minZoom}
              max={maxZoom}
              step={zoomStep}
              value={zoomVal}
              onChange={(zoom: any) => {
                setZoomVal(zoom > maxZoom ? maxZoom : zoom)
              }}
            />
            <button onClick={addZoomVal} disabled={isMaxZoom}>
              ＋
            </button>
          </div>
        </Modal>
      ) : loading && screens['xs'] ? (
        <Loading />
      ) : (
        <></>
      )}
    </div>
  )

  if (modalTitle) return renderComponent(modalTitle)

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

interface ImgCropProps {
  src: string
  aspect?: number
  shape?: 'rect' | 'round'
  grid?: boolean
  quality?: number

  zoom?: 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
  handleCompletedCropUpdate?: any
}

export default forwardRef(ImgCrop)
