import { IGame, EntityType } from "../game";
import relativeVector from "./relativevector";

export default function attachmentManager(game: IGame) {
    mp.events.add("SERVER:LoadAttachments", () => {
        attachmentMngr.register("char_creator_1", "prop_beggers_sign_04", 28422, new mp.Vector3(0, 0, 0), new mp.Vector3(0, 0, 0));
        attachmentMngr.register("ammobox", "gr_prop_gr_crate_mag_01a", 28422, new mp.Vector3(0, -0.18, -0.18), new mp.Vector3(0, 0, 0));
        attachmentMngr.register("binbag", "prop_cs_rub_binbag_01", 28422, new mp.Vector3(0.08, 0.0, -0.03), new mp.Vector3(270.0, 0.0, 25.0));
        attachmentMngr.register("weapondeal", "ex_prop_crate_ammo_bc", "chassis_dummy", new mp.Vector3(0.08, -0.9, -0.2), new mp.Vector3(0, 0, 0));
        attachmentMngr.register("weapondeal1", "ex_office_swag_guns02", "chassis_dummy", new mp.Vector3(0, 0.8, 0), new mp.Vector3(0, 0, 0));
        attachmentMngr.register("weapondeal2", "w_sg_pumpshotgun", "weapondeal2w_sg_pumpshotgun", new mp.Vector3(0.4, 1.6, 0.62), new mp.Vector3(90, 0, 180));
    });

    const attachmentMngr =
    {
        attachments: {},

        addFor: function (entityRage, id) {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }

            let e = game.attachments.get(entity);

            if (this.attachments.hasOwnProperty(id)) {
                if (e.__attachmentObjects == undefined) { e.__attachmentObjects = []; }
                if (!e.__attachmentObjects.hasOwnProperty(id)) {
                    let attInfo = this.attachments[id];
                    let object = mp.objects.new(attInfo.model, entityRage.position);

                    object.attachTo(entityRage.handle,
                        (typeof (attInfo.boneName) === 'string') ? entityRage.getBoneIndexByName(attInfo.boneName) : entityRage.getBoneIndex(attInfo.boneName),
                        attInfo.offset.x, attInfo.offset.y, attInfo.offset.z,
                        attInfo.rotation.x, attInfo.rotation.y, attInfo.rotation.z,
                        false, false, false, false, 2, true);

                    e.__attachmentObjects[id] = object;
                }
            }
            /*   else {
                   mp.game.graphics.notify(`Static Attachments Error: ~r~Unknown Attachment Used: ~w~0x${id.toString(16)}`);
               } */
        },

        removeFor: function (entityRage, id) {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }
            let e = game.attachments.get(entity);

            if (e.__attachmentObjects.hasOwnProperty(id)) {
                let obj = e.__attachmentObjects[id];

                obj.destroy();
                delete e.__attachmentObjects[id];
            }
        },

        initFor: function (entityRage) {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }

            let e = game.attachments.get(entity);
            if (e != null) {
                for (let attachment of e.__attachments) {
                    attachmentMngr.addFor(entityRage, attachment);
                }
            }
        },

        shutdownFor: function (entityRage) {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }

            let e = game.attachments.get(entity);
            if (e != null) {
                for (let attachment of e.__attachments) {
                    attachmentMngr.removeFor(entityRage, attachment);
                }
            }
        },

        register: function (id, model, boneName, offset, rotation) {
            if (typeof (id) === 'string') {
                id = mp.game.joaat(id);
            }

            if (typeof (model) === 'string') {
                model = mp.game.joaat(model);
            }

            if (!this.attachments.hasOwnProperty(id)) {
                if (mp.game.streaming.isModelInCdimage(model)) {
                    this.attachments[id] =

                    {
                        id: id,
                        model: model,
                        offset: offset,
                        rotation: rotation,
                        boneName: boneName
                    };
                }
                else {
                    mp.game.graphics.notify(`Static Attachments Error: ~r~Invalid Model(0x${model.toString(16)})`);
                }
            }
            else {
                mp.game.graphics.notify("Static Attachments Error: ~r~Duplicate Entry");
            }
        },

        unregister: function (id) {
            if (typeof (id) === 'string') {
                id = mp.game.joaat(id);
            }

            if (this.attachments.hasOwnProperty(id)) {
                this.attachments[id] = undefined;
            }
        },

        addLocal: function (attachmentName) {
            if (typeof (attachmentName) === 'string') {
                attachmentName = mp.game.joaat(attachmentName);
            }

            let entity = game.players.local;
            let e = game.attachments.get(entity);

            if (!e.__attachments || e.__attachments.indexOf(attachmentName) === -1) {
                mp.events.callRemote("staticAttachments.Add", attachmentName.toString(36));
            }
        },

        removeLocal: function (attachmentName) {
            if (typeof (attachmentName) === 'string') {
                attachmentName = mp.game.joaat(attachmentName);
            }

            let entity = game.players.local;
            let e = game.attachments.get(entity);

            if (e.__attachments && e.__attachments.indexOf(attachmentName) !== -1) {
                mp.events.callRemote("staticAttachments.Remove", attachmentName.toString(36));
            }
        },

        getAttachments: function () {
            return Object.assign({}, this.attachments);
        }
    };

    mp.events.add("entityStreamIn", (entityRage) => {
        if (entityRage.type === "player" || entityRage.type === "vehicle") {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }
            let e = game.attachments.get(entity);
            if (e != null) {
                if (e.__attachments) {
                    game.wait(5000);
                    attachmentMngr.initFor(entityRage);
                }
            }
        }
    });

    mp.events.add("entityStreamOut", (entityRage) => {
        if (entityRage == mp.players.local.vehicle) {
            return;
        }
        if (entityRage.type === "player" || entityRage.type === "vehicle") {
            let e = game.attachments.at(entityRage.remoteId);

            if (e != null) {
                if (e.__attachmentObjects) {
                    //game.wait(2500);
                    attachmentMngr.shutdownFor(entityRage);
                }
            }
        }
    });

    mp.events.addDataHandler("attachmentsData", (entityRage, data) => {
        let newAttachments = (data != null) ? data.split('|').map(att => parseInt(att, 36)) : [];

        if (entityRage.handle !== 0) {
            let entity;
            if (entityRage.type === "player") {
                entity = game.players.at(entityRage.remoteId);
            } else if (entityRage.type === "vehicle") {
                entity = game.vehicles.at(entityRage.remoteId);
            }
            let e = game.attachments.get(entity);
            if (e == null) {
                let __attachments = [];
                let __attachmentObjects = [];
                e = game.attachments.set(entity, __attachments, __attachmentObjects);
            }

            let oldAttachments = e.__attachments;

            if (!oldAttachments) {
                oldAttachments = [];
                e.__attachmentObjects = [];
            }

            // process outdated first
            for (let attachment of oldAttachments.keys()) {
                var obj = oldAttachments[attachment];
                if (newAttachments.indexOf(obj) === -1) {
                    attachmentMngr.removeFor(entityRage, obj);
                }
            }

            // then new attachments
            for (let attachment of newAttachments) {
                if (oldAttachments.indexOf(attachment) === -1) {
                    attachmentMngr.addFor(entityRage, attachment);
                }
            }
            e.__attachments = newAttachments;
        }
    });

    function InitAttachmentsOnJoin() {
        game.players.forEach(_player => {
            let player = mp.players.at(_player.remoteId);

            if (!player) {
                return;
            }

            let e = game.attachments.get(_player);
            if (e == null) {
                let __attachments = [];
                let __attachmentObjects = [];
                e = game.attachments.set(_player, __attachments, __attachmentObjects);
            }
            let data = player.getVariable("attachmentsData");

            if (data && data.length > 0) {
                let atts = data.split('|').map(att => parseInt(att, 36));
                e.__attachments = atts;
                e.__attachmentObjects = [];
            }
        });

        game.vehicles.forEach(_veh => {
            let vehicle = mp.vehicles.at(_veh.remoteId);

            if (!vehicle) {
                return;
            }

            let e = game.attachments.get(_veh);
            if (e == null) {
                let __attachments = [];
                let __attachmentObjects = [];
                e = game.attachments.set(_veh, __attachments, __attachmentObjects);
            }
            let data = vehicle.getVariable("attachmentsData");

            if (data && data.length > 0) {
                let atts = data.split('|').map(att => parseInt(att, 36));
                e.__attachments = atts;
                e.__attachmentObjects = [];
            }
        });
    }

    InitAttachmentsOnJoin();
}