import {
    TransitionPropertyVectorXBehavior
} from "../../../../../model/game/story/behaviors/generic/TransitionPropertyVectorXBehavior.js";
import { TweenVector1Behavior } from "../../../../../model/game/util/behavior/TweenVector1Behavior.js";
import { TweenVector3Behavior } from "../../../../../model/game/util/behavior/TweenVector3Behavior.js";
import { max2 } from "../../../core/math/max2.js";
import { min2 } from "../../../core/math/min2.js";
import { Light } from "../../graphics/ecs/light/Light.js";
import Mesh, { MeshFlags } from "../../graphics/ecs/mesh/Mesh.js";
import Trail2D from "../../graphics/ecs/trail2d/Trail2D.js";
import { Trail2DFlags } from "../../graphics/ecs/trail2d/Trail2DFlags.js";
import { ParticleEmitter } from "../../graphics/particles/particular/engine/emitter/ParticleEmitter.js";
import { ParticleEmitterFlag } from "../../graphics/particles/particular/engine/emitter/ParticleEmitterFlag.js";
import { SequenceBehavior } from "../../intelligence/behavior/composite/SequenceBehavior.js";
import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorComponent.js";
import { DieBehavior } from "../../intelligence/behavior/ecs/DieBehavior.js";
import { DelayBehavior } from "../../intelligence/behavior/util/DelayBehavior.js";
import { SoundEmitter } from "../../sound/ecs/emitter/SoundEmitter.js";
import { Transform } from "../transform/Transform.js";

/**
 * @readonly
 * @type {number}
 */
const SHUTDOWN_GRACE_PERIOD = 60;

/**
 *
 * @type {Map<Class|function, function(T,entity?:Entity,createEntity?:function,createEntityContext?:*):number>}
 */
const component_shutdown = new Map();

/**
 * @template T
 * @param {Class<T>} type
 * @param {function(T,entity?:Entity,createEntity?:function,createEntityContext?:*):number} method
 */
function addShutdown(type, method) {
    component_shutdown.set(type, method);
}

addShutdown(ParticleEmitter, emitter => {

    //stop emission
    emitter.clearFlag(ParticleEmitterFlag.Emitting);

    //figure out how long the emitter should stay alive
    const maxLife = emitter.computeMaxEmittingParticleLife(SHUTDOWN_GRACE_PERIOD);

    return maxLife;
});

addShutdown(Trail2D, trail => {
    trail.clearFlag(Trail2DFlags.Spawning);

    return trail.maxAge;
});

addShutdown(Mesh, (mesh, builder, createEntity, createEntityThisArg) => {

    /**
     *
     * @type {Transform}
     */
    const transform = builder.getComponent(Transform);

    let delay = 0;

    if (mesh !== null && transform !== null) {

        if (mesh.getFlag(MeshFlags.Loaded | MeshFlags.InView) && !transform.scale.isZero()) {
            const scale = new TweenVector3Behavior();

            scale.startValue.copy(transform.scale);
            scale.targetValue.set(0, 0, 0);
            scale.target = transform.scale;

            scale.duration = 0.2;

            delay = max2(scale.duration, delay);

            const eb = createEntity.call(createEntityThisArg);

            eb.add(BehaviorComponent.from(SequenceBehavior.from([
                scale,
                DieBehavior.create()
            ])));

        } else {
            transform.scale.set(0, 0, 0);
        }

    }


    return delay;
});

addShutdown(Light, (light, builder, createEntity, createEntityThisArg) => {


    let delay = 0.2;


    const eb = createEntity.call(createEntityThisArg);

    eb.add(BehaviorComponent.from(SequenceBehavior.from([
        TransitionPropertyVectorXBehavior.from({
            component: 'Light',
            path: 'intensity',
            target: [0],
            duration: delay,
            entity: builder.id
        }),
        DieBehavior.create()
    ])));

    return delay;
});

addShutdown(SoundEmitter, (soundEmitter, builder, createEntity, createEntityThisArg) => {
    let delay = 0;

    if (soundEmitter.volume.getValue() > 0) {

        const tracks = soundEmitter.tracks.asArray();

        const n = tracks.length;


        for (let i = 0; i < n; i++) {
            const soundTrack = tracks[i];

            if (soundTrack.volume > 0) {

                const setVolume = new TweenVector1Behavior();

                setVolume.startValue = soundEmitter.volume.getValue();
                setVolume.targetValue = 0;

                setVolume.target = soundEmitter.volume;

                setVolume.duration = 2.7;

                delay = SHUTDOWN_GRACE_PERIOD;

                const eb = createEntity.call(createEntityThisArg);

                eb.add(BehaviorComponent.from(SequenceBehavior.from([
                    DelayBehavior.from(SHUTDOWN_GRACE_PERIOD - setVolume.duration),
                    setVolume,
                    DieBehavior.create()
                ])));

                break;
            }
        }
    }

    return delay;
});

/**
 *
 * @param {Entity} builder
 * @param {function():Entity} createEntity
 * @param {*} [createEntityThisArg]
 * @return {number} duration in seconds until the entity is completely hidden
 */
export function hideEntityGracefully(builder, createEntity, createEntityThisArg) {
    if (!builder.isBuilt) {
        // already destroyed
        return 0;
    }

    let delay = 0;

    const components = builder.components;

    const component_count = components.length;

    for (let i = 0; i < component_count; i++) {
        const component = components[i];

        const shutdown_method = component_shutdown.get(Object.getPrototypeOf(component).constructor);

        if (shutdown_method === undefined) {
            continue;
        }

        const sd = shutdown_method(component, builder, createEntity, createEntityThisArg);

        if (Number.isNaN(sd) || !Number.isFinite(sd)) {
            continue;
        }

        delay = max2(sd, delay);
    }

    delay = min2(delay, SHUTDOWN_GRACE_PERIOD);

    return delay;
}
