import { LazyResizableRawTexture } from '../LazyResizableRawTexture';
import { ProductMeshesGroupRenderInfo } from '../ProductMeshesGroupRenderInfo';
import { PROPERTIES_SAMPLER } from '../ShaderConstants';
import { AbstractMesh, Mesh, Scene } from '../babylonjs-import';
import { UniformsAndDefinesAndSamplers } from './CullingMaterial';
import { CustomDepthMaterial, DISCARD_DITHER_TRANSPARENT } from './CustomDepthMaterial';

/** @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported. */ /** */
export class IfcMeshDepthMaterial extends CustomDepthMaterial {
    constructor(
        name: string,
        scene: Scene,
        renderingInfo: ProductMeshesGroupRenderInfo,
        diffuseTexture: LazyResizableRawTexture,
        propertiesTexture: LazyResizableRawTexture
    ) {
        super(name, scene, renderingInfo, diffuseTexture, propertiesTexture);

        this.visualSettings.ifc.transparency.onPropertyChanged.add((event) => {
            if (event.property === 'ditheringOptions') {
                this.isDirty = true;
            }
        });
    }

    readonly _type = 'IfcMeshDepthMaterial';

    override getUniformsAndDefinesAndSamplers(): UniformsAndDefinesAndSamplers {
        const uniformsAndDefines = super.getUniformsAndDefinesAndSamplers();

        if (this.visualSettings.ifc.transparency.ditheringOptions.ditherDiscardDepth) {
            uniformsAndDefines.defines.push(DISCARD_DITHER_TRANSPARENT);
        }

        uniformsAndDefines.samplers.push(PROPERTIES_SAMPLER);

        return uniformsAndDefines;
    }

    override bindFunction(mesh: AbstractMesh): void {
        super.bindFunction(mesh);
        if (mesh instanceof Mesh) {
            //check if mesh is a twinfinity or babylon mesh
            const isBabylonMesh = !mesh.twinfinity?.ifc;
            if (isBabylonMesh) {
                throw new Error(
                    'The mesh bound to this material is an Babylon mesh, Babylon meshes should not be assigned the IFC mesh depth material (this material)'
                );
            }
        }

        const effect = this.getEffect();

        if (this.propertiesTexture) {
            effect.setTexture(PROPERTIES_SAMPLER, this.propertiesTexture.getTexture(mesh.getScene()));
        }
    }
}
