import React, { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import type { MapControlsProps } from '@react-three/drei';
import { MapControls } from '@react-three/drei';
import { useCameraVisibleArea } from '@game/hooks/game/camera';
import { isFloatEqual } from '@core/lib/base/is-float-equal';

const minDistance = 25;
const maxDistance = 200;

const minPolarAngle = 0.41;
const maxPolarAngle = 1.1;

const minAzimuthAngle = 0.2 + Math.PI / 2;
const maxAzimuthAngle = 0.2 + Math.PI / 2;

function easeOutCubic(x: number): number {
  return 1 - Math.pow(1 - x, 3);
}

export function Camera() {
  const ref = useRef<MapControlsProps>();
  const lastDistance = useRef<number>();

  useCameraVisibleArea();

  useFrame((state, delta) => {
    const controls = ref.current!;
    const distance = controls.getDistance?.();

    if (!distance || (lastDistance.current && isFloatEqual(distance, lastDistance.current, 1e-3))) {
      return;
    }

    lastDistance.current = distance;

    const ratio = (distance - minDistance) / (maxDistance - minDistance);
    const newPolarAngle = maxPolarAngle - (maxPolarAngle - minPolarAngle) * easeOutCubic(ratio);

    controls.minPolarAngle = newPolarAngle;
    controls.maxPolarAngle = newPolarAngle;
    controls.setPolarAngle?.(newPolarAngle);
  });

  return (
    <MapControls
      // @ts-ignore
      ref={ref}
      dampingFactor={0.1}
      zoomSpeed={2}
      panSpeed={0.5}
      minPolarAngle={minPolarAngle}
      maxPolarAngle={maxPolarAngle}
      minAzimuthAngle={minAzimuthAngle}
      maxAzimuthAngle={maxAzimuthAngle}
      minDistance={minDistance}
      maxDistance={maxDistance}
    />
  );
}
