import { nanoid } from 'nanoid';
import EventEmitter, { InvalidArgumentError, inspect, } from './utilities/EventEmitter.js';
import { ERR_NOT_ENTERED_SPACE } from './Errors.js';
export default class Locations extends EventEmitter {
    constructor(space, presenceUpdate) {
        super();
        this.space = space;
        this.presenceUpdate = presenceUpdate;
        this.lastLocationUpdate = {};
    }
    async processPresenceMessage(message) {
        // Only an update action is currently a valid location update.
        if (message.action !== 'update')
            return;
        // Emit updates only if they are different than the last held update.
        if (!message.data.locationUpdate.id ||
            this.lastLocationUpdate[message.connectionId] === message.data.locationUpdate.id) {
            return;
        }
        const update = message.data.locationUpdate;
        const { previous } = update;
        const member = await this.space.members.getByConnectionId(message.connectionId);
        if (member) {
            this.emit('update', {
                member,
                currentLocation: member.location,
                previousLocation: previous,
            });
            this.lastLocationUpdate[message.connectionId] = message.data.locationUpdate.id;
        }
    }
    async set(location) {
        const self = await this.space.members.getSelf();
        if (!self) {
            throw ERR_NOT_ENTERED_SPACE();
        }
        const update = {
            profileUpdate: {
                id: null,
                current: self.profileData,
            },
            locationUpdate: {
                id: nanoid(),
                previous: self.location,
                current: location,
            },
        };
        const extras = this.space.locks.getLockExtras(self.connectionId);
        await this.presenceUpdate(update, extras);
    }
    subscribe(listenerOrEvents, listener) {
        try {
            super.on(listenerOrEvents, listener);
        }
        catch (e) {
            if (e instanceof InvalidArgumentError) {
                throw new InvalidArgumentError('Locations.subscribe(): Invalid arguments: ' + inspect([listenerOrEvents, listener]));
            }
            else {
                throw e;
            }
        }
    }
    unsubscribe(listenerOrEvents, listener) {
        try {
            super.off(listenerOrEvents, listener);
        }
        catch (e) {
            if (e instanceof InvalidArgumentError) {
                throw new InvalidArgumentError('Locations.unsubscribe(): Invalid arguments: ' + inspect([listenerOrEvents, listener]));
            }
            else {
                throw e;
            }
        }
    }
    async getSelf() {
        const self = await this.space.members.getSelf();
        return self ? self.location : null;
    }
    async getOthers() {
        const members = await this.space.members.getOthers();
        return members.reduce((acc, member) => {
            acc[member.connectionId] = member.location;
            return acc;
        }, {});
    }
    async getAll() {
        const members = await this.space.members.getAll();
        return members.reduce((acc, member) => {
            acc[member.connectionId] = member.location;
            return acc;
        }, {});
    }
}
