import { serializable } from "../../engine/engine_serialization_decorator.js";
import { FrameEvent } from "../../engine/engine_setup.js";
import { Behaviour, GameObject } from "../Component.js";
import { BaseUIComponent } from "./BaseUIComponent.js";
import { Graphic } from "./Graphic.js";
import { type ICanvasGroup, type IHasAlphaFactor } from "./Interfaces.js";


/**
 * [CanvasGroup](https://engine.needle.tools/docs/api/CanvasGroup) is a UI component that allows you to control the transparency and interactivity of a group of UI elements.
 * By adjusting the alpha property, you can fade in or out all child UI elements simultaneously.
 * The interactable and blocksRaycasts properties let you enable or disable user interaction for the entire group.
 * @summary Group UI elements to control transparency and interactivity
 * @category User Interface
 * @group Components
 */
export class CanvasGroup extends Behaviour implements ICanvasGroup {
    @serializable()
    get alpha(): number {
        return this._alpha;
    }
    set alpha(val: number) {
        if (val === this._alpha) return;
        this._alpha = val;
        this.markDirty();
    }

    get isCanvasGroup() { return true; }

    private _alpha: number = 1;

    @serializable()
    interactable: boolean = true;
    @serializable()
    blocksRaycasts: boolean = true;


    private _isDirty: boolean = false;
    private markDirty() {
        if (this._isDirty) return;
        this._isDirty = true;
        this.startCoroutine(this.applyChangesDelayed(), FrameEvent.OnBeforeRender);
    }

    private *applyChangesDelayed() {
        this._isDirty = false;
        this.applyChangesNow();
    }

    private _buffer: Graphic[] = [];
    private applyChangesNow() {
        this._buffer.length = 0;
        for (const ch of GameObject.getComponentsInChildren(this.gameObject, BaseUIComponent, this._buffer)) {
            const hasAlphaFactor = ch as any as IHasAlphaFactor;
            if (hasAlphaFactor.setAlphaFactor)
                hasAlphaFactor.setAlphaFactor(this._alpha);
        }
    }
}