import { useRef, useEffect } from "react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import {
  useAzimuth,
  useElevation,
  useShadows,
  useSunPosition,
  useFloorItems,
  useWallItems,
  useTileDistance,
} from "../../../store/store";
import * as CONSTANTS from "../../../types/world/worldConstants";
const shadowWorker = new Worker(
  new URL(
    "../../../services/factoryBuilder/webWorkers/shadowWorker",
    import.meta.url
  )
);

export default function Shadows() {
  const { shadows, setShadows } = useShadows();
  const { sunPosition, setSunPosition } = useSunPosition();
  const lightRef = useRef<THREE.DirectionalLight | null>(null);
  const targetRef = useRef<THREE.Object3D | null>(null);
  const { controls, gl } = useThree();
  const { elevation, setElevation } = useElevation();
  const { azimuth, setAzimuth } = useAzimuth();
  const { floorItems } = useFloorItems();
  const { wallItems } = useWallItems();
  const { planeValue } = useTileDistance();

  useEffect(() => {
    gl.shadowMap.enabled = true;
    gl.shadowMap.type = THREE.PCFShadowMap;
  }, [gl, floorItems, wallItems]);

  useEffect(() => {
    if (lightRef.current && targetRef.current) {
      lightRef.current.target = targetRef.current;
    }
  }, []);

  useEffect(() => {
    shadowWorker.onmessage = (event) => {
      const { lightPosition, controlsTarget } = event.data;
      if (lightRef.current && targetRef.current && controls) {
        lightRef.current.position.copy(lightPosition);
        targetRef.current.position.copy(controlsTarget);
      }
    };
  }, [shadowWorker, controls]);

  const updateShadows = () => {
    if (controls && shadowWorker) {
      const offsetDistance = CONSTANTS.shadowConfig.shadowOffset;
      const controlsTarget = (controls as any).getTarget();
      shadowWorker.postMessage({ controlsTarget, sunPosition, offsetDistance });
    }
  };

  useEffect(() => {
    if (controls && shadows) {
      updateShadows();
      (controls as any).addEventListener("update", updateShadows);
      return () => {
        (controls as any).removeEventListener("update", updateShadows);
      };
    }
  }, [controls, elevation, azimuth, shadows]);

  return (
    <>
      {/* {(lightRef.current?.shadow) &&
        <cameraHelper visible={shadows} args={[lightRef.current.shadow.camera]} />
      } */}
      <directionalLight
        ref={lightRef}
        castShadow={shadows}
        shadow-mapSize-width={CONSTANTS.shadowConfig.shadowmapSizewidth}
        shadow-mapSize-height={CONSTANTS.shadowConfig.shadowmapSizeheight}
        shadow-camera-far={CONSTANTS.shadowConfig.shadowcamerafar}
        shadow-camera-near={CONSTANTS.shadowConfig.shadowcameranear}
        shadow-camera-top={CONSTANTS.shadowConfig.shadowcameratop}
        shadow-camera-bottom={CONSTANTS.shadowConfig.shadowcamerabottom}
        shadow-camera-left={CONSTANTS.shadowConfig.shadowcameraleft}
        shadow-camera-right={CONSTANTS.shadowConfig.shadowcameraright}
        shadow-bias={CONSTANTS.shadowConfig.shadowbias}
        shadow-normalBias={CONSTANTS.shadowConfig.shadownormalBias}
      />
      <object3D ref={targetRef} />
      <mesh
        position={CONSTANTS.shadowConfig.shadowMaterialPosition}
        rotation={CONSTANTS.shadowConfig.shadowMaterialRotation}
        receiveShadow
      >
        {/* <planeGeometry
          args={[CONSTANTS.planeConfig.width, CONSTANTS.planeConfig.height]}
        />
        <shadowMaterial
          opacity={CONSTANTS.shadowConfig.shadowMaterialOpacity}
          transparent
        /> */}
        <planeGeometry args={[planeValue.width, planeValue.height]} />
        <shadowMaterial
          opacity={CONSTANTS.shadowConfig.shadowMaterialOpacity}
          transparent
        />
      </mesh>
    </>
  );
}
