import {
    ClampToEdgeWrapping,
    Color,
    FrontSide,
    GLSL3,
    LinearFilter,
    NormalBlending,
    ShaderMaterial,
    UniformsLib,
    UniformsUtils,
    Vector2,
    Vector4 as ThreeVector4
} from 'three';
import TerrainShader from "../shaders/TerrainShader.js";
import { whitePixelTexture } from "../texture/whitePixelTexture.js";

/**
 *
 * @param {Vector2} [gridResolution]
 * @param {Texture} [splatMap]
 * @param {THREE.DataTexture2DArray} [diffuseMaps]
 * @param {Texture} [lightMap]
 * @return {ShaderMaterial}
 * @constructor
 */
export function SplatMaterial(
    {
        gridResolution,
        splatMap,
        diffuseMaps,
        lightMap
    }
) {


    const uniforms = UniformsUtils.merge([
        UniformsLib.common,
        UniformsLib.specularmap,
        UniformsLib.envmap,
        UniformsLib.aomap,
        UniformsLib.lightmap,
        UniformsLib.emissivemap,
        UniformsLib.fog,
        UniformsLib.lights,
        {
            "splatWeightMap": {
                type: "t",
                value: null
            },

            "splatResolution": {
                type: 'v2',
                value: new Vector2(1, 1)
            },

            "gridResolution": {
                type: "v2",
                value: new Vector2(1, 1)
            },
            uGridTransform: {
                type: 'v4',
                value: new ThreeVector4()
            },
            "gridBorderWidth": {
                type: "f",
                value: 0.1
            },

            "materialScalesMap": { type: "t", value: null },
            "diffuseMaps": { type: "t", value: null },
            "diffuseGridOverlayMap": { type: "t", value: null },
            "diffuseGridOverlaySprite": { type: "t", value: whitePixelTexture() }
        },
        {
            "emissive": { type: "c", value: new Color(0x000000) },
            "specular": { type: "c", value: new Color(0xFFFFFF) },
            "shininess": { type: "f", value: 0 },
            "envMapIntensity": { value: 1 } // temporary
        },
        {
            "f_CloudsTime": { type: "f", value: 0 },
            "f_CloudsAmount": { type: "f", value: 0.9 },
            "f_CloudsIntensity": { type: "f", value: 0.3 },

            "v_CloudsSpeed_0": { type: "v2", value: new Vector2(0.03, -0.03) },
            "v_CloudsSpeed_1": { type: "v2", value: new Vector2(0.011, -0.011) },
            "v_CloudsSpeed_2": { type: "v2", value: new Vector2(0.023, -0.023) },

            "v_CloudsSize_0": { type: "v2", value: new Vector2(40, 40) },
            "v_CloudsSize_1": { type: "v2", value: new Vector2(20, 20) },
            "v_CloudsSize_2": { type: "v2", value: new Vector2(10, 10) },

            "t_Clouds_0": { type: "t", value: null },
            "t_Clouds_1": { type: "t", value: null },
            "t_Clouds_2": { type: "t", value: null }
        }
    ]);

    if (gridResolution !== undefined) {
        uniforms.gridResolution.value.set(gridResolution.x, gridResolution.y);
    }

    const sm = new ShaderMaterial({

        uniforms: uniforms,
        vertexShader: TerrainShader.vertexShader,
        fragmentShader: TerrainShader.fragmentShader,
        side: FrontSide,
        blending: NormalBlending,
        depthTest: true,
        depthWrite: true,
        transparent: false,
        lights: true,
        defines: {
            SPLAT_LAYER_COUNT: 4,
            SHADOWMAP_CLOUDS: false,
            DIFFUSE_GRAIN: false
        },
        glslVersion: GLSL3
    });

    sm.depthWrite = true;
    sm.transparent = false;

    uniforms.diffuse.value = new Color(0xFFFFFF);

    if (splatMap !== void 0) {
        //TODO: check power of two
        splatMap.wrapS = splatMap.wrapT = ClampToEdgeWrapping;
        splatMap.minFilter = LinearFilter;
        splatMap.magFilter = LinearFilter;
        uniforms.splatMap.value = splatMap;
    }

    if (diffuseMaps !== void 0) {
        uniforms.diffuseMaps.value = diffuseMaps;
    }

    if (lightMap !== void 0) {
        sm.aoMap = true;
        uniforms.aoMap.value = lightMap;
        uniforms.aoMapIntensity.value = 0.7;
    }

    sm.extensions.derivatives = true; //needed for rendering grid
    sm.needsUpdate = true;

    sm.isSplatMaterial = true;

    return sm;
}
