import React, { useEffect, useState, useRef, useCallback, useContext } from 'react'
import './ImageLoader.scss'
import { ImageLoader } from './index'
import { useControls, useTransformEffect, useTransformContext } from 'react-zoom-pan-pinch'
import { useClickOutside } from '$themehooks'
import { RootDocumentContext } from '$themeservices'

const Zoom = ({
  className,
  src,
  setShowLoading,
  activeImage,
  index,
  setIsImageZoomed,
}) => {
  const [scale, setScale] = useState(1)
  const [isPanning, setIsPanning] = useState()
  const transformCoordinates = useRef(null)
  const [allowPanning, setAllowPanning] = useState(false)
  const containerRef = useRef(null)
  const { resetTransform, zoomIn, zoomOut } = useControls()
  const context = useTransformContext()
  const { rootElement } = useContext(RootDocumentContext)()

  useEffect(() => {
    if (scale > 1 && index !== activeImage) {
      resetTransform()
    }
    return () => resetTransform()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeImage])

  useTransformEffect(({ state, instance }) => {
    setIsImageZoomed(state.scale > 1)
    setScale(state.scale)
    setIsPanning(instance.isPanning)
  })

  const handleClickOutside = useCallback(() => {
    setAllowPanning(false)
    resetTransform()
  }, [resetTransform])

  useClickOutside(containerRef, handleClickOutside, rootElement)

  const onClick = (e) => {
    if (isPanning) return
    transformCoordinates.current = {
      x: e.pageX,
      y: e.pageY
    }
    const { transformState } = context
    if (transformState.scale === 1) {
      zoomIn()
    } else {
      zoomOut()
    }
    setAllowPanning(!allowPanning)
  }

  const onMouseMove = (e) => {
    if (allowPanning) {
      const currentCoordinates = {
        x: e.pageX,
        y: e.pageY
      }
      const deltaX = transformCoordinates.current.x - currentCoordinates.x
      const deltaY = transformCoordinates.current.y - currentCoordinates.y
      transformCoordinates.current = currentCoordinates

      const newCoordinateX = context.transformState.positionX + deltaX
      const newCoordinateY = context.transformState.positionY + deltaY
      context.setTransformState(context.transformState.scale, newCoordinateX, newCoordinateY)
    }
  }

  const onMouseLeave = () => {
    setAllowPanning(false)
  }

  const onMouseEnter = (e) => {
    if (scale > 1) {
      transformCoordinates.current = { x: e.pageX, y: e.pageY }
      setAllowPanning(true)
    }
  }

  const getPinchPanClasses = () => {
    if (isPanning) return 'panning'
    return scale > 1 ? 'zoomOut' : 'zoomIn'
  }

  return (
    <div ref={containerRef}>
      <ImageLoader
        onMouseLeave={onMouseLeave}
        onMouseEnter={onMouseEnter}
        onClick={onClick}
        onMouseMove={onMouseMove}
        className={`${className || ''} ${getPinchPanClasses()}`}
        setShowLoading={setShowLoading}
        src={src}
        activeImage={activeImage}
      />
    </div>
  )
}

export default Zoom
