import { combine_hash } from "../../../../core/collection/array/combine_hash.js";
import { computeHashArray } from "../../../../core/collection/array/computeHashArray.js";
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
import { computeHashColor } from "./computeHashColor.js";
import { planeHash } from "./planeHash.js";
import { textureHashById } from "./textureHashById.js";

/**
 *
 * @param {Material|MeshStandardMaterial|ShaderMaterial} material
 * @returns {number}
 */
export function computeMaterialHash(material) {

    let hash = combine_hash(
        computeHashFloat(material.alphaTest),
        material.blendDst,
        material.blendDstAlpha === null ? 0 : computeHashFloat(material.blendDstAlpha),
        material.blendEquation,
        material.blendEquationAlpha === null ? 0 : computeHashFloat(material.blendEquationAlpha),
        material.blending,
        material.blendSrc,
        material.blendSrcAlpha === null ? 0 : computeHashFloat(material.blendSrcAlpha),
        material.clipIntersection ? 0 : 1,
        material.clippingPlanes === null ? 0 : computeHashArray(material.clippingPlanes, planeHash),
        material.clipShadows ? 0 : 1,
        material.colorWrite ? 0 : 1,
        material.depthFunc,
        material.depthTest ? 0 : 1,
        material.depthWrite ? 0 : 1,
        material.fog ? 0 : 1,
        computeHashFloat(material.opacity),
        material.polygonOffset ? 0 : 1,
        computeHashFloat(material.polygonOffsetFactor),
        computeHashFloat(material.polygonOffsetUnits),
        computeStringHash(material.precision),
        material.premultipliedAlpha ? 0 : 1,
        material.dithering ? 0 : 1,
        material.flatShading ? 0 : 1,
        material.side,
        material.transparent ? 0 : 1,
        computeStringHash(material.type),
        material.vertexColors ? 0 : 1,
        material.visible ? 0 : 1,
    );


    if (material.isMeshStandardMaterial) {
        hash = combine_hash(
            hash,
            computeHashColor(material.color),
            computeHashFloat(material.roughness),
            computeHashFloat(material.metalness),
            textureHashById(material.map),
            textureHashById(material.lightMap),
            computeHashFloat(material.lightMapIntensity),
            textureHashById(material.aoMap),
            computeHashFloat(material.aoMapIntensity),
            computeHashColor(material.emissive),
            computeHashFloat(material.emissiveIntensity),
            textureHashById(material.emissiveMap),
            computeHashFloat(material.envMapIntensity),
            textureHashById(material.bumpMap),
            textureHashById(material.normalMap),
        );
    } else if (material.isShaderMaterial) {
        hash ^= material.lights ? 0 : 1;
    }

    return hash;
}
