import { useMemo, useRef } from "react";
import { Color, DoubleSide, ShaderMaterial } from "three";
import { useFrame } from "@react-three/fiber";
import { useSceneStore } from "../../../../store/scene/useSceneStore";
import useShaderReader from "../../../../utils/scene/useShaderReader";

import plane1Vertex from "../../../../assets/shaders/plane/plane1.vert.glsl";
import plane1Fragment from "../../../../assets/shaders/plane/plane1.frag.glsl";

import plane2Vertex from "../../../../assets/shaders/plane/plane2.vert.glsl";
import plane2Fragment from "../../../../assets/shaders/plane/plane2.frag.glsl";

import plane3Vertex from "../../../../assets/shaders/plane/plane3.vert.glsl";
import plane3Fragment from "../../../../assets/shaders/plane/plane3.frag.glsl";

type PlaneMaterialProps = {
    color?: string;
    variant?: "plane1" | "plane2" | "plane3";
    transparent?: boolean;
    opacity?: number;
    depthWrite?: boolean;
    depthTest?: boolean;
    polygonOffset?: boolean;
    polygonOffsetFactor?: number;
    polygonOffsetUnits?: number;
};

function PlaneMaterial({
    color = "white",
    variant = "plane1",
    transparent = false,
    opacity = 1,
    depthWrite = true,
    depthTest = true,
    polygonOffset = false,
    polygonOffsetFactor,
    polygonOffsetUnits,
}: Readonly<PlaneMaterialProps>) {
    const { limitFps } = useSceneStore();
    const materialRef = useRef<ShaderMaterial | null>(null);

    const vertexShaderUrl = variant === "plane1" ? plane1Vertex : variant === "plane2" ? plane2Vertex : variant === "plane3" ? plane3Vertex : plane1Vertex;

    const fragmentShaderUrl = variant === "plane1" ? plane1Fragment : variant === "plane2" ? plane2Fragment : variant === "plane3" ? plane3Fragment : plane1Fragment;

    const vertexShader = useShaderReader(vertexShaderUrl);
    const fragmentShader = useShaderReader(fragmentShaderUrl);

    const polygonOffsetProps = polygonOffset
        ? {
              polygonOffsetFactor: polygonOffsetFactor ?? -1,
              polygonOffsetUnits: polygonOffsetUnits ?? -1,
          }
        : {};

    const material = useMemo(() => {
        if (!vertexShader || !fragmentShader) return null;

        return new ShaderMaterial({
            side: DoubleSide,
            vertexShader,
            fragmentShader,
            uniforms: {
                uOuterColor: { value: new Color(color) },
                uTime: { value: 0 },
            },
            transparent,
            opacity,
            depthWrite,
            depthTest,
            polygonOffset,
            ...polygonOffsetProps,
        });
    }, [color, vertexShader, fragmentShader, transparent, opacity, depthWrite, depthTest, polygonOffset, polygonOffsetFactor, polygonOffsetUnits]);

    useFrame(({ clock }) => {
        if (materialRef.current && !limitFps) {
            materialRef.current.uniforms.uTime.value = clock.getElapsedTime();
        }
    });

    if (!material) return null;
    return <primitive object={material} ref={materialRef} attach="material" />;
}

export default PlaneMaterial;
