import { CubeUVReflectionMapping, EquirectangularReflectionMapping, SRGBColorSpace, Vector4 } from "three";
import { AssetReference } from "./engine_addressables.js";
import { createFlatTexture, createTrilightTexture } from "./engine_shaders.js";
import { getParam } from "./engine_utils.js";
// import { LightProbeGenerator } from "three/examples/jsm/lights/LightProbeGenerator.js"
const debug = getParam("debugenvlight");
/** @internal */
export var AmbientMode;
(function (AmbientMode) {
    AmbientMode[AmbientMode["Skybox"] = 0] = "Skybox";
    AmbientMode[AmbientMode["Trilight"] = 1] = "Trilight";
    AmbientMode[AmbientMode["Flat"] = 3] = "Flat";
    AmbientMode[AmbientMode["Custom"] = 4] = "Custom";
})(AmbientMode || (AmbientMode = {}));
/** @internal */
export var DefaultReflectionMode;
(function (DefaultReflectionMode) {
    DefaultReflectionMode[DefaultReflectionMode["Skybox"] = 0] = "Skybox";
    DefaultReflectionMode[DefaultReflectionMode["Custom"] = 1] = "Custom";
})(DefaultReflectionMode || (DefaultReflectionMode = {}));
/**
 * The RendererData class is used to manage the lighting settings of a scene.
 * It is created and used within the Needle Engine Context.
 */
export class RendererData {
    context;
    constructor(context) {
        this.context = context;
        this.context.pre_update_callbacks.push(this.preUpdate.bind(this));
    }
    /**
     * The id of the currently active scene light settings (source identifier).
     */
    _currentLightSettingsId;
    _sceneLightSettings;
    get currentLightSettingsId() {
        return this._currentLightSettingsId;
    }
    preUpdate() {
        const time = this.context.time;
        this._timevec4.x = time.time;
        this._timevec4.y = Math.sin(time.time);
        this._timevec4.z = Math.cos(time.time);
        this._timevec4.w = time.deltaTime;
    }
    _timevec4 = new Vector4();
    /** Time data used for custom shaders
     * x: time
     * y: sin(time)
     * z: cos(time)
     * w: deltaTime
     */
    get timeVec4() {
        return this._timevec4;
    }
    /** the current environment intensity */
    get environmentIntensity() {
        if (!this._sceneLightSettings)
            return 1;
        if (!this._currentLightSettingsId)
            return 1;
        const settings = this._sceneLightSettings.get(this._currentLightSettingsId);
        if (settings)
            return settings.ambientIntensity; // * Math.PI * .5;
        return 1;
    }
    /** Get all currently registered scene light settings */
    get sceneLightSettings() { return this._sceneLightSettings?.values(); }
    /** set the scene lighting from a specific scene. Will disable any previously enabled lighting settings */
    enable(sourceId) {
        if (sourceId instanceof AssetReference)
            sourceId = sourceId.url;
        const settings = this._sceneLightSettings?.get(sourceId);
        if (!settings) {
            if (debug)
                console.warn("No light settings found for", sourceId);
            return false;
        }
        if (debug)
            console.log("Enable scene light settings", sourceId, settings);
        if (sourceId !== this._currentLightSettingsId && this._currentLightSettingsId) {
            this.disable(this._currentLightSettingsId);
        }
        this._currentLightSettingsId = sourceId;
        settings.enabled = true;
        return true;
    }
    /** disable the lighting of a specific scene, will only have any effect if it is currently active */
    disable(sourceId) {
        if (sourceId instanceof AssetReference)
            sourceId = sourceId.url;
        if (sourceId === null || sourceId === undefined)
            return false;
        const settings = this._sceneLightSettings?.get(sourceId);
        if (!settings) {
            return false;
        }
        if (debug)
            console.log("Disable scene light settings", sourceId, settings);
        settings.enabled = false;
        return true;
    }
    /**
     * Enables the currently active scene lighting (if any), returns the id of the enabled lighting.
     * @returns The id of the enabled lighting, or null if no lighting is currently active.
     */
    enableCurrent() {
        if (this._currentLightSettingsId) {
            this.enable(this._currentLightSettingsId);
            return this._currentLightSettingsId ?? null;
        }
        return null;
    }
    /** Disables the currently active scene lighting (if any), returns the id of the previously active lighting
     * @returns The id of the previously active lighting, or null if no lighting was active.
     */
    disableCurrent() {
        if (this._currentLightSettingsId) {
            const prev = this._currentLightSettingsId;
            this.disable(this._currentLightSettingsId);
            return prev;
        }
        return null;
    }
    /** @internal */
    internalRegisterSceneLightSettings(sceneLightSettings) {
        const sourceId = sceneLightSettings.sourceId;
        if (!sourceId) {
            console.error("Missing source id for scene light settings, can not register:", sceneLightSettings);
            return;
        }
        if (debug)
            console.log("Register " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
        if (!this._sceneLightSettings)
            this._sceneLightSettings = new Map();
        this._sceneLightSettings.set(sourceId, sceneLightSettings);
    }
    /** @internal */
    internalUnregisterSceneLightSettings(sceneLightSettings) {
        const sourceId = sceneLightSettings.sourceId;
        if (!sourceId) {
            console.error("Missing source id for scene light settings, can not unregister:", sceneLightSettings);
            return;
        }
        if (debug)
            console.log("Unregister " + sceneLightSettings?.sourceId + " lighting", sceneLightSettings);
        if (!this._sceneLightSettings)
            return;
        this._sceneLightSettings.delete(sourceId);
    }
    /** @internal */
    internalRegisterReflection(sourceId, reflectionTexture) {
        if (debug)
            console.log("Register reflection", sourceId, reflectionTexture);
        const h = new LightData(this.context, reflectionTexture, 1);
        this._lighting[sourceId] = h;
    }
    /** @internal */
    internalGetReflection(sourceId) {
        return this._lighting[sourceId];
    }
    __currentReflectionId = null;
    /** @internal */
    internalEnableReflection(sourceId) {
        this.__currentReflectionId = sourceId;
        const settings = this._sceneLightSettings?.get(sourceId);
        if (debug) {
            console.log("Enable reflection", sourceId, settings ? AmbientMode[settings.ambientMode] : "Unknown ambient mode", settings);
        }
        switch (settings?.ambientMode) {
            case AmbientMode.Skybox:
            case AmbientMode.Custom:
                // only set environment reflection when ambient mode is skybox or custom
                const existing = this.internalGetReflection(sourceId);
                if (existing && existing.Source) {
                    if (debug)
                        console.log("Setting environment reflection", existing);
                    const scene = this.context.scene;
                    const tex = existing.Source;
                    if (tex.mapping !== CubeUVReflectionMapping) {
                        tex.mapping = EquirectangularReflectionMapping;
                    }
                    scene.environment = tex;
                    scene.environmentIntensity = this.environmentIntensity || 1;
                    return tex;
                }
                else if (debug)
                    console.warn("Could not find reflection for source", sourceId);
                break;
        }
        if (settings?.environmentReflectionSource === DefaultReflectionMode.Custom) {
            switch (settings?.ambientMode) {
                case AmbientMode.Trilight:
                    if (settings.ambientTrilight) {
                        const colors = settings.ambientTrilight;
                        const tex = createTrilightTexture(colors[0], colors[1], colors[2], 64, 64);
                        tex.colorSpace = SRGBColorSpace;
                        tex.mapping = EquirectangularReflectionMapping;
                        this.context.scene.environment = tex;
                        return tex;
                    }
                    else
                        console.error("Missing ambient trilight", settings.sourceId);
                case AmbientMode.Flat:
                    if (settings.ambientLight) {
                        const tex = createFlatTexture(settings.ambientLight, 64);
                        tex.colorSpace = SRGBColorSpace;
                        tex.mapping = EquirectangularReflectionMapping;
                        this.context.scene.environment = tex;
                        return tex;
                    }
                    else
                        console.error("Missing ambientlight", settings.sourceId);
            }
        }
        return null;
    }
    /** @internal */
    internalDisableReflection(sourceId) {
        if (sourceId && sourceId !== this.__currentReflectionId) {
            if (debug)
                console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId);
            return;
        }
        if (debug)
            console.log("Disable reflection", sourceId);
        const scene = this.context.scene;
        scene.environment = null;
    }
    _lighting = {};
}
export class LightData {
    get Source() { return this._source; }
    // get Array(): number[] | undefined { return this._sphericalHarmonicsArray; }
    _source;
    // private _sphericalHarmonicsArray?: number[];
    // private _context: Context;
    // private _sphericalHarmonics: SphericalHarmonics3 | null = null;
    // private _ambientScale: number = 1;
    // private _lightProbe?: LightProbe;
    constructor(_context, tex, _ambientScale = 1) {
        // this._context = context;
        this._source = tex;
        // this._ambientScale = ambientScale;
        if (tex.mapping !== CubeUVReflectionMapping) {
            tex.mapping = EquirectangularReflectionMapping;
        }
    }
}
//# sourceMappingURL=engine_scenelighting.js.map