import { float_to_uint8 } from "../../../../core/binary/float_to_uint8.js";
import { SerializationMetadata } from "../../../ecs/components/SerializationMetadata.js";
import Entity from "../../../ecs/Entity.js";
import { AbstractContextSystem } from "../../../ecs/system/AbstractContextSystem.js";
import { SystemEntityContext } from "../../../ecs/system/SystemEntityContext.js";
import { Transform } from "../../../ecs/transform/Transform.js";
import {
    PARTICLE_ATTRIBUTE_COLOR,
    PARTICLE_ATTRIBUTE_POSITION
} from "../../particles/particular/engine/emitter/PARTICLE_ATTRIBUTES.js";
import { ParticleEmitter } from "../../particles/particular/engine/emitter/ParticleEmitter.js";
import { ParticleEmitterFlag } from "../../particles/particular/engine/emitter/ParticleEmitterFlag.js";
import { ParticleLayer } from "../../particles/particular/engine/emitter/ParticleLayer.js";
import { Sprite } from "./Sprite.js";

class Context extends SystemEntityContext {
    constructor() {
        super();

        this.__emitter = new ParticleEmitter();
        this.__layer = new ParticleLayer();

        this.__layer.emissionRate = 0;
        this.__layer.emissionImmediate = 1;
        this.__layer.steps.reset();
        this.__layer.particleLife.set(999999999, 999999999);

        this.__emitter.addLayer(this.__layer);

        this.__emitter_entity = new Entity()
            .add(this.__emitter)
            .add(new Transform())
            .add(SerializationMetadata.Transient);
    }

    __copy_transform() {

        /**
         *
         * @type {Transform}
         */
        const transform = this.components[1];

        this.__emitter_entity.getComponent(Transform).copy(transform);

        const emitter = this.__emitter;


        emitter.particles?.writeAttributeVector3(0, PARTICLE_ATTRIBUTE_POSITION, transform.position.x, transform.position.y, transform.position.z);

        emitter.setFlag(ParticleEmitterFlag.ParticleBoundsNeedUpdate);

    }

    link() {
        if (this.__is_linked) {
            return;
        }

        super.link();


        /**
         *
         * @type {Transform}
         */
        const transform = this.components[1];

        transform.position.onChanged.add(this.__copy_transform, this);
        transform.scale.onChanged.add(this.__copy_transform, this);

        /**
         *
         * @type {Sprite}
         */
        const sprite = this.components[0];

        this.__layer.imageURL = sprite.url;
        this.__layer.particleSize.set(sprite.size, sprite.size);

        const emitter = this.__emitter;

        if (!emitter.getFlag(ParticleEmitterFlag.Built)) {
            //particle pool needs to be set up first
            emitter.build();
        }

        if (!emitter.getFlag(ParticleEmitterFlag.Initialized)) {
            //particles are not initialized, do that
            emitter.initialize();
        }

        emitter.particles?.writeAttributeVector4(
            0, PARTICLE_ATTRIBUTE_COLOR,
            float_to_uint8(sprite.color.r), float_to_uint8(sprite.color.g), float_to_uint8(sprite.color.b), float_to_uint8(sprite.opacity.getValue())
        );


        this.__copy_transform();

        emitter.computeBoundingBox();

        this.__emitter_entity.build(this.getDataset());
    }

    unlink() {
        if (!this.__is_linked) {
            return;
        }

        /**
         *
         * @type {Transform}
         */
        const transform = this.components[1];

        transform.position.onChanged.remove(this.__copy_transform, this);
        transform.scale.onChanged.remove(this.__copy_transform, this);

        super.unlink();

        this.__emitter_entity.destroy();
    }
}

export class SpriteSystemPE extends AbstractContextSystem {
    constructor() {
        super(Context);


        this.dependencies = [Sprite, Transform];
    }
}
