import Utils from "../Utils/Utils";

let instance;
const instanceKey = 'evt_392994';

export class Events {
    static DOCUMENT_LOADED = 'DOCUMENT_LOADED';
    static HASH_CHANGE = 'HASH_CHANGE';
    static WINDOW_RESIZE = 'WINDOW_RESIZE';
    static DOCUMENT_CLICK = 'DOCUMENT_CLICK';
    static BACKGROUND_INIT = 'BACKGROUND_INIT';
    static BACKGROUND_PAGE_ENTER = 'BACKGROUND_PAGE_ENTER';
    static BACKGROUND_PAGE_LEAVE = 'BACKGROUND_PAGE_LEAVE';
    static SOUND_LOGIN_REQUIRED_POPUP = 'SOUND_LOGIN_REQUIRED_POPUP';
    static SOUND_PRO_REQUIRED_POPUP = 'SOUND_PRO_REQUIRED_POPUP';
    static BCK_LOGIN_REQUIRED_POPUP = 'BCK_LOGIN_REQUIRED_POPUP';
    static BCK_PRO_REQUIRED_POPUP = 'BCK_PRO_REQUIRED_POPUP';
    static SHOW_FE_ERROR = 'SHOW_FE_ERROR';
    static STOP_BACKGROUND_SOUNDS = 'STOP_BACKGROUND_SOUNDS';
    static PAUSE_BACKGROUND_SOUNDS = 'PAUSE_BACKGROUND_SOUNDS';
    static PLAYLIST_PLAY = 'PLAYLIST_PLAY';
    static PLAYLIST_AUTO_PLAY = 'PLAYLIST_AUTO_PLAY';
    static DEFAULT_BACKGROUND_CHANGE = 'DEFAULT_BACKGROUND_CHANGE';
    static OPEN_SELECT_BACKGROUND_FOR_PLAYLIST = 'OPEN_SELECT_BACKGROUND_FOR_PLAYLIST';
    static PLAYLIST_BACKGROUND_SELECTED = 'PLAYLIST_BACKGROUND_SELECTED';
    static CLOSE_SELECT_BACKGROUND_POPUP = 'CLOSE_SELECT_BACKGROUND_POPUP';
    static GO_TO_SLEEP_MODE = 'GO_TO_SLEEP_MODE';
    static WAKE_UP = 'WAKE_UP';
    static DEPLOY_PLAYLIST_BACKGROUND = 'DEPLOY_PLAYLIST_BACKGROUND';
    static REMOVE_PLAYLIST_BACKGROUND = 'REMOVE_PLAYLIST_BACKGROUND';
}

export class Event {
    constructor(key, callback, target = null) {
        this.key = key;
        this.callback = callback;
        this.target = target;
    }
}

class EventBus {
    _events = [];

    constructor(key) {
        if (key !== instanceKey) {
            throw new Error('Cannot instantiate like this');
        }
    }

    registerEvent(event, callback) {
        if (!(event instanceof Event)) {
            throw new Error('Only Event instances are accepted');
        }
        if (!Events[event.key]) {
            throw new Error('Event key has not been registered');
        }
        if (this._eventExists(event) !== -1) {
            console.log('Cannot register Event. Already registered!');
            return;
        }
        this._events.push(event);
    }

    registerDynamicEvent(event, callback) {
        if (!event?.key) {
            console.error('Missing event key', event);
            return;
        }
        const eventToAdd = {
            key: event.key,
            callback: callback || event.callback,
            target: event.target || null
        };
        this._events.push(eventToAdd);
    }

    triggerEvent(key, payload) {
        if (!Events[key]) {
            throw new Error('triggerEvent: Event key has not been registered');
        }
        for (const event of this._events) {
            if (event.key === key) {
                if (Utils.isFunction(event.callback)) {
                    event.callback(payload);
                }
            }
        }
    }

    triggerDynamicEvent(key, payload) {
        for (const event of this._events) {
            if (event.key === key) {
                if (Utils.isFunction(event.callback)) {
                    event.callback(key, payload);
                }
            }
        }
    }

    removeEvent(event) {
        if (!(event instanceof Event)) {
            throw new Error('Only Event instances are accepted');
        }
        if (!Events[event.key]) {
            throw new Error('Event key has not been registered');
        }
        const index = this._eventExists(event);
        if (index !== -1) {
            // console.log('FOUND EV TO REMOVE at', index);
            this._events.splice(index, 1);
        }
    }

    _eventExists(event) {
        let index = -1;
        for (let i = 0; i < this._events.length; i++) {
            if (Utils.isEqual(event, this._events[i])) {
                index = i;
                break;
            }
        }
        return index;
    }

    static getInstance() {
        if (!instance) {
            instance = new EventBus(instanceKey);
        }
        return instance;
    }
}

export default EventBus;