interface IGame {
    wait(ms: number);
    events: IEvents;
    ui: IUi;

    players: IPlayerPool;
    vehicles: IVehiclePool;
    attachments: IEntityAttachmentPool;

    disableDefaultEngineBehaviour(): void;
}

interface IEvents {
    translateEventName(event: EventName): string;
    add(event: EventName | string, callback: (...args: any[]) => void): void;
    addCef(event: string, callback: (args: any[]) => void): void;
    callServer(event: string, args?: any[] | any): void;
    bindKey(key: Key, hold: boolean, callback: Function);
    unbindKey(key: Key, hold: boolean, callback?: Function);

    onEntityStreamIn(callback: (entity: IEntity) => void): void;
    onPlayerEnterVehicle(callback: (entity: IVehicle, seat: VehicleSeat) => void): void;
    onPlayerExitVehicle(callback: () => void): void;
    onPlayerCommand(callback: (cmd: string) => void);
}

interface IUi {
    sendChatMessage(message: string);
    openBrower(path: string): IBrowser;
    setCursor(freeze: boolean, show: boolean): void;
    toggleChat(toggle: boolean): void;
    setHelpText(text: string): void;
    clearHelpText(): void;
    inMenu: boolean;
    inChat: boolean;
}

interface IBrowser {
    close(): void;
    executeJs(script: string);
}

interface IEntity {
    id: number;
    remoteId: number;
    type: EntityType;
    getSharedData<T>(key: string): T;
}

interface IPlayer extends IEntity {
    inVehicle: boolean;
    name: string;
    vehicle: IVehicle;
}

interface IEntityAttachments {
    remoteId: any;
    __attachments: any[];
    __attachmentObjects: any[];
}

interface IVehicle extends IEntity {
    isSeatFree(seat: VehicleSeat): boolean;
    setEngineStatus(status: boolean, instantly: boolean, otherwise: boolean);
    setUndriveable(status: boolean);
    setDoorsLocked(state: boolean);
    setDoorShut(door: number, instantly: boolean);
    setDoorOpen(door: number, loose: boolean, instantly: boolean);
}

interface IEntityPool<TEntity> {
    at(id: number): TEntity;
    forEach(fn: (entity: TEntity) => void): void;
}

interface IPlayerPool extends IEntityPool<IPlayer> {
    local: IPlayer;
}

interface IEntityAttachmentPool {
    attachmentPool: IEntityAttachments[];
    find(entity: EntityMp): IEntityAttachments;
    remove(entity: IEntity): void;
    set(entity: IEntity, attachments: any[], attachmentObjects: any[]): IEntityAttachments;
    at(handle: any): IEntityAttachments;
    get(entity: IEntity): IEntityAttachments;
}

interface IVehiclePool extends IEntityPool<IVehicle> {
}

enum EntityType {
    Unknown,
    Player,
    Vehicle
}

interface AccountData {
    Username: string;
    CreatedAt: Date;

    GroupName: string,
    GroupRank: string,
}

interface VehicleData {
    EngineState: boolean;
    Locked: boolean;

    Doors: { [door: number]: number };
}

enum DoorState {
    DoorClosed,
    DoorOpen,
    DoorBroken,
}

enum EventName {
    PlayerCommand,
    Tick,
    EntityStreamIn
}

enum Key {
    ENTER = 0x0D,
    M = 0x4D,
    T = 0x54,
    X = 0x58,
    E = 0x45
}

enum VehicleSeat {
    Driver,
    CoDriver,
    LeftPassenger,
    RightPassenger,
    ExtraSeat1,
    ExtraSeat2,
    ExtraSeat3,
    ExtraSeat4
}

export {
    IGame,
    IEvents,
    IUi,
    IBrowser,

    IPlayer,
    IEntityAttachments,
    IEntityAttachmentPool,
    IVehicle,
    IEntity,
    IEntityPool,
    IPlayerPool,
    IVehiclePool,

    EventName,
    Key,
    VehicleSeat,
    EntityType,
    AccountData,
    VehicleData,
    DoorState
}