/**
 * Creates a Points Material, which can be extended with GL nodes.
 *
 * @remarks
 * This node can create children, which will be GL nodes. The GLSL code generated by the nodes will extend the Material.
 *
 */
import {NodeParamsConfig} from '../utils/params/ParamsConfig';
import {
	UniformsTransparencyParamConfig,
	UniformsTransparencyController,
	UniformsTransparencyControllers,
} from './utils/UniformsTransparencyController';
import {
	AdvancedCommonController,
	AdvancedCommonControllers,
	AdvancedCommonParamConfig,
} from './utils/AdvancedCommonController';
import {ShaderAssemblerPoints} from '../gl/code/assemblers/materials/Points';
import {TypedBuilderMatNode, BaseBuilderParamConfig} from './_BaseBuilder';
import {AssemblerName} from '../../poly/registers/assemblers/_BaseRegister';
import {Poly} from '../../Poly';
import {FogParamConfig, UniformFogController, UniformFogControllers} from './utils/UniformsFogController';
import {DefaultFolderParamConfig} from './utils/DefaultFolder';
import {AdvancedFolderParamConfig} from './utils/AdvancedFolder';
import {CustomMaterialName} from '../../../core/geometry/Material';
import {Material} from 'three';
import {PointsMaterial} from 'three';
import {PointsSizeController, PointsParamConfig, PointsSizeControllers} from './utils/PointsSizeController';
import {MatType} from '../../poly/registers/nodes/types/Mat';
import {
	CustomMaterialPointsParamConfig,
	materialPointsAssemblerCustomMaterialRequested,
} from './utils/customMaterials/CustomMaterialPoints';

interface PointsBuilderControllers
	extends AdvancedCommonControllers,
		PointsSizeControllers,
		UniformFogControllers,
		UniformsTransparencyControllers {}
interface PointsBuilderMaterial extends PointsMaterial {
	vertexShader: string;
	fragmentShader: string;
	customMaterials: {
		[key in CustomMaterialName]?: Material;
	};
}

class PointsBuilderMatParamsConfig extends CustomMaterialPointsParamConfig(
	FogParamConfig(
		AdvancedCommonParamConfig(
			BaseBuilderParamConfig(
				/* advanced */ AdvancedFolderParamConfig(
					UniformsTransparencyParamConfig(PointsParamConfig(DefaultFolderParamConfig(NodeParamsConfig)))
				)
			)
		)
	)
) {}
const ParamsConfig = new PointsBuilderMatParamsConfig();

export class PointsBuilderMatNode extends TypedBuilderMatNode<
	PointsBuilderMaterial,
	ShaderAssemblerPoints,
	PointsBuilderMatParamsConfig
> {
	override paramsConfig = ParamsConfig;
	static override type() {
		return MatType.POINTS_BUILDER;
	}
	public override usedAssembler(): Readonly<AssemblerName.GL_POINTS> {
		return AssemblerName.GL_POINTS;
	}
	protected _createAssemblerController() {
		return Poly.assemblersRegister.assembler(this, this.usedAssembler());
	}
	public override customMaterialRequested(customName: CustomMaterialName): boolean {
		return materialPointsAssemblerCustomMaterialRequested(this, customName);
	}
	readonly controllers: PointsBuilderControllers = {
		advancedCommon: new AdvancedCommonController(this),
		pointsSize: new PointsSizeController(this),
		uniformFog: new UniformFogController(this),
		uniformTransparency: new UniformsTransparencyController(this),
	};
	protected override controllersList = Object.values(this.controllers);
	override async cook() {
		this._material = this._material || this.createMaterial();
		await Promise.all(this.controllersPromises(this._material));

		this.compileIfRequired(this._material);

		this.setMaterial(this._material);
	}
}
