import { Object3D } from "three";

import { isDevEnvironment } from "../../engine/debug/index.js";
import { addComponent } from "../../engine/engine_components.js";
import { foreachComponentEnumerator } from "../../engine/engine_gameobject.js";
import { ConstructorConcrete, IComponent } from "../../engine/engine_types.js";
import { getParam } from "../../engine/engine_utils.js";
import { type PostProcessingEffect } from "./PostProcessingEffect.js";

export const debug = getParam("debugpost");

export type IPostProcessingManager = IComponent & {
    get isPostProcessingManager(): boolean;
    addEffect(effect: PostProcessingEffect): void;
    removeEffect(effect: PostProcessingEffect): void;
}


let PostprocessingManagerType: ConstructorConcrete<IPostProcessingManager> | null = null;

export function setPostprocessingManagerType(type: ConstructorConcrete<IPostProcessingManager>) {
    PostprocessingManagerType = type;
}

export function findPostProcessingManager(effect: PostProcessingEffect): IPostProcessingManager | null {
    let obj = effect.gameObject as Object3D | null;
    while (obj) {
        for (const comp of foreachComponentEnumerator(obj)) {
            if ((comp as unknown as IPostProcessingManager).isPostProcessingManager === true) {
                return comp as unknown as IPostProcessingManager;
            }
        }
        obj = obj.parent;
    }
    return null;
}

export function getPostProcessingManager(effect: PostProcessingEffect): IPostProcessingManager | null {
    let manager: IPostProcessingManager | null = findPostProcessingManager(effect);
    if (!manager) {
        if (PostprocessingManagerType) {
            if (debug)
                console.warn("Adding postprocessing manager to the scene.");
            const scene = effect.scene;
            manager = addComponent(scene, PostprocessingManagerType);
        }
        else {
            if (isDevEnvironment())
                console.warn("No post processing manager found");
        }
    }
    return manager;
}