import { createContext, useContext, useState } from 'react'
import type { PropsWithChildren } from 'react'
import { m, useReducedMotion } from 'framer-motion'

import { usePointerPosition } from '@/lib/hooks'
import { isTouchDevice } from '@/lib//utilities'

import CircleButton from '@/components/shared/CircleButton'

type OrbProps = {
  label?: string
}

type ContextValue = {
  isVisible: boolean
  position: { x: number; y: number }
  showOrb(): void
  hideOrb(): void
}

export const OrbContext = createContext<ContextValue>({
  isVisible: false,
  position: { x: 0, y: 0 },
  showOrb: () => {},
  hideOrb: () => {},
})

// Provider component that wraps your app and makes the orb object
// available to any child component that calls useOrb()
export const OrbProvider = ({ children }: PropsWithChildren) => {
  const [isVisible, setIsVisible] = useState(false)
  const { x, y } = usePointerPosition()

  const value: ContextValue = {
    isVisible,
    position: { x, y },
    showOrb: () => setIsVisible(true),
    hideOrb: () => setIsVisible(false),
  }

  return <OrbContext.Provider value={value}>{children}</OrbContext.Provider>
}

// Consumer component for our OrbContext
export const OrbConsumer = OrbContext.Consumer

// Orb component for the UI
const Orb = ({ label = 'View' }: OrbProps) => {
  const {
    position: { x, y },
    isVisible,
  } = useContext(OrbContext)

  return (
    <m.div
      className="hidden md:block fixed top-0 left-0 origin-top-left pointer-events-none z-top"
      initial={{ opacity: 0, scale: 0.5 }}
      animate={{
        opacity: isVisible ? 1 : 0,
        scale: isVisible ? 1 : 0.5,
        x,
        y,
      }}
      transition={{
        type: 'spring',
        damping: 25,
        stiffness: 150,
        restDelta: 0.001,
        duration: 100,
      }}
      aria-hidden
    >
      <CircleButton as="span" className="-translate-x-1/2 -translate-y-1/2 transform-gpu" disableHover>
        {label}
      </CircleButton>
    </m.div>
  )
}

// Hook for child components to use
export const useOrb = () => {
  const { showOrb, hideOrb } = useContext(OrbContext)
  const prefersReducedMotion = useReducedMotion()
  const disableOrb = prefersReducedMotion || isTouchDevice()

  return {
    orbPointerEvents: disableOrb
      ? {}
      : {
          onPointerOver: () => showOrb(),
          onPointerOut: () => hideOrb(),
        },
    orbClasses: disableOrb ? '' : 'md:cursor-none',
    Orb,
  }
}

// HOC to wrap component with OrbProvider
// export const withOrbProvider = (WrappedComponent: any) => {
//   return (
//     <OrbProvider>
//       <WrappedComponent />
//     </OrbProvider>
//   )
// }
