import { IEntity, IPlayer, IEntityAttachments, IEntityAttachmentPool, IPlayerPool, IVehicle, IVehiclePool, VehicleSeat, EntityType } from "../../game";
import { parseJson } from "../../util";
import game from "../..";

class RageEntity implements IEntity {
    private entity: EntityMp;
    public __attachments: any[];
    public __attachmentObjects: any[];

    get id(): number {
        if (!this.entity) {
            return null;
        }

        return this.entity.id;
    }

    get attachments(): number {
        var color = this.entity.getVariable("nametagColor");
        if (!color)
            return 0;
        return color;
    }

    get handle() {
        return this.entity.handle;
    }

    get remoteId(): number {
        if (!this.entity) {
            return null;
        }

        return this.entity.remoteId;
    }

    constructor(entity: EntityMp) {
        this.entity = entity;
    }

    get type(): EntityType {
        if (!this.entity) {
            return null;
        }

        switch (this.entity.type) {
            case 'vehicle': return EntityType.Vehicle;
            case 'player': return EntityType.Player;
            default: return EntityType.Unknown;
        }
    }

    getSharedData<T>(key: string): T {
        if (!this.entity) {
            return null;
        }

        var data = this.entity.getVariable(key);
        if (typeof data !== 'undefined') {
            return parseJson<T>(<string>data);
        }

        return null;
    }
}

class RagePlayer extends RageEntity implements IPlayer {
    private player: PlayerMp;

    get name(): string {
        return this.player.name;
    }

    get nametagColor(): number {
        var color = this.player.getVariable("nameTagColor");
        game.ui.sendChatMessage(`player = ${this.player.name} - color = ${color}`);
        if (!color)
            return 0;
        return color;
    }

    get vehicle(): IVehicle {
        if (!this.player) {
            return null;
        }

        var veh: VehicleMp = this.player.vehicle;
        return veh ? new RageVehicle(veh) : null;
    }

    get inVehicle(): boolean {
        if (!this.player) {
            return false;
        }

        return this.player.isInAnyVehicle(false);
    }

    constructor(player: PlayerMp) {
        super(player);
        this.player = player;
    }
}

class RageAttachments implements IEntityAttachments {
    remoteId: any;
    public __attachments: any[];
    public __attachmentObjects: any[];

    constructor(entity: IEntity, attachments: any[], attachmentObjects: any[]) {
        this.remoteId = entity.remoteId;
        this.__attachments = attachments;
        this.__attachmentObjects = attachmentObjects;
    }
}

class RageEntityAttachmentPool implements IEntityAttachmentPool {
    public attachmentPool: IEntityAttachments[];
    remove(entity: IEntity) {
        for (let obj of this.attachmentPool.keys()) {
            if (entity.remoteId == this.attachmentPool[obj].remoteId) delete this.attachmentPool[obj];
        }
    }
    find(entity: EntityMp): IEntityAttachments {

        for (let i of this.attachmentPool.keys()) {
            let pool = this.attachmentPool[i];
            for (let obj of pool.__attachmentObjects) {
                if (entity == obj) { return pool; }
            }
        }
        return null;
    }

    set(entity: IEntity, attachments: any[], attachmentObjects: any[]): IEntityAttachments {

        if (!this.attachmentPool) {
            let e = new RageAttachments(entity, attachments, attachmentObjects);
            this.attachmentPool = [];
            this.attachmentPool.push(e);

            return e;
        }

        for (let obj of this.attachmentPool.keys()) {
            if (entity.remoteId == this.attachmentPool[obj].remoteId) { this.remove(entity); }
        }

        let e = new RageAttachments(entity, attachments, attachmentObjects);
        this.attachmentPool.push(e);
        return e;        
    }

    at(remoteId: any): IEntityAttachments {
        if (!this.attachmentPool) {
            return null;
        }

        for (let obj of this.attachmentPool.keys()) {
            if (remoteId == this.attachmentPool[obj].remoteId) { return this.attachmentPool[obj]; }
        }
        return null;
    }

    get(entity: IEntity): IEntityAttachments {
        if (!this.attachmentPool) {

            return null;
        }

        for (let obj of this.attachmentPool.keys()) {
            if (entity.remoteId == this.attachmentPool[obj].remoteId) { return this.attachmentPool[obj]; }
        }
        return null;
    }
}

class RagePlayerPool implements IPlayerPool {
    get local(): IPlayer {
        return new RagePlayer(mp.players.local);
    }

    at(id: number): IPlayer {
        return new RagePlayer(mp.players.atRemoteId(Number(id)));
    }

    forEach(fn: (entity: IPlayer) => void): void {
        mp.players.forEach(e => {
            fn(new RagePlayer(e));
        });
    }
}


class RageVehicle extends RageEntity implements IVehicle {
    private vehicle: VehicleMp;

    constructor(vehicle: VehicleMp) {
        if (!vehicle) {
            throw "Vehicle is null / undefined"
        }
        super(vehicle);
        this.vehicle = vehicle;
    }

    isSeatFree(seat: VehicleSeat): boolean {
        return this.vehicle.isSeatFree(<number>seat - 1);
    }

    setEngineStatus(status: boolean, instantly: boolean, otherwise: boolean) {
        this.vehicle.setEngineOn(status, instantly, otherwise);
    }

    setUndriveable(status: boolean) {
        this.vehicle.setUndriveable(status);
    }

    setDoorsLocked(state: boolean) {
        this.vehicle.setDoorsLocked(state ? 2 : 1);
    }

    setDoorOpen(door: number, loose: boolean, instantly: boolean) {
        this.vehicle.setDoorOpen(door, loose, instantly);
    }

    setDoorShut(door: number, instantly: boolean) {
        this.vehicle.setDoorShut(door, instantly);
    }
}



class RageVehiclePool implements IVehiclePool {
    at(id: number): IVehicle {
        var veh = mp.vehicles.atRemoteId(Number(id));

        if (!veh) {
            return null;
        }

        return new RageVehicle(veh);
    }

    forEach(fn: (entity: IVehicle) => void): void {
        mp.vehicles.forEach(e => {
            if (!e) {
                game.ui.sendChatMessage("forEach - e is null");
                return;
            }
            fn(new RageVehicle(e));
        })
    }
}

export {
    RageEntity,
    RagePlayer,
    RagePlayerPool,
    RageAttachments,
    RageEntityAttachmentPool,
    RageVehicle,
    RageVehiclePool,
   
}