import * as MessageTray from './messageTray.js';
import Shell from 'gi://Shell';
import * as ParentalControlsManager from '../misc/parentalControlsManager.js';
import * as Signals from '../misc/signals.js';

class AppFavorites extends Signals.EventEmitter {
    constructor() {
        super();

        // Filter the apps through the user’s parental controls.
        this._parentalControlsManager = ParentalControlsManager.getDefault();
        this._parentalControlsManager.connect('app-filter-changed',
            () => this._updateFavorites());

        this._appSystem = Shell.AppSystem.get_default();
        this._appSystem.connect('installed-changed',
            () => this._updateFavorites());

        this.FAVORITE_APPS_KEY = 'favorite-apps';
        this._favorites = {};
        global.settings.connect(`changed::${this.FAVORITE_APPS_KEY}`,
            () => this._updateFavorites());

        this.reload();
    }

    _updateFavorites() {
        const oldIDs = this._getIds();
        this.reload();
        const newIDs = this._getIds();

        const haveChanged = () => {
            if (oldIDs.length !== newIDs.length)
                return true;

            return oldIDs.some(
                (id, i) => id !== newIDs[i] || !this.isFavorite(id));
        };

        if (haveChanged())
            this.emit('changed');
    }

    reload() {
        const ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
        const apps = ids.map(id => this._appSystem.lookup_app(id))
                      .filter(app => app !== null && this._parentalControlsManager.shouldShowApp(app.app_info));
        this._favorites = {};
        for (let i = 0; i < apps.length; i++) {
            const app = apps[i];
            this._favorites[app.get_id()] = app;
        }
    }

    _getIds() {
        const ret = [];
        for (const id in this._favorites)
            ret.push(id);
        return ret;
    }

    getFavoriteMap() {
        return this._favorites;
    }

    getFavorites() {
        const ret = [];
        for (const id in this._favorites)
            ret.push(this._favorites[id]);
        return ret;
    }

    isFavorite(appId) {
        return appId in this._favorites;
    }

    _addFavorite(appId, pos) {
        if (appId in this._favorites)
            return false;

        const app = Shell.AppSystem.get_default().lookup_app(appId);

        if (!app)
            return false;

        if (!this._parentalControlsManager.shouldShowApp(app.app_info))
            return false;

        const ids = this._getIds();
        if (pos === -1)
            ids.push(appId);
        else
            ids.splice(pos, 0, appId);
        global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
        return true;
    }

    addFavoriteAtPos(appId, pos) {
        if (!this._addFavorite(appId, pos))
            return;

        const app = Shell.AppSystem.get_default().lookup_app(appId);

        this._showNotification(_('%s Pinned to Dash').format(app.get_name()),
            null,
            () => this._removeFavorite(appId));
    }

    addFavorite(appId) {
        this.addFavoriteAtPos(appId, -1);
    }

    moveFavoriteToPos(appId, pos) {
        this._removeFavorite(appId);
        this._addFavorite(appId, pos);
    }

    _removeFavorite(appId) {
        if (!(appId in this._favorites))
            return false;

        const ids = this._getIds().filter(id => id !== appId);
        global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
        return true;
    }

    removeFavorite(appId) {
        const ids = this._getIds();
        const pos = ids.indexOf(appId);

        const app = this._favorites[appId];
        if (!this._removeFavorite(appId))
            return;

        this._showNotification(_('%s Unpinned From Dash').format(app.get_name()),
            null,
            () => this._addFavorite(appId, pos));
    }

    _showNotification(title, body, undoCallback) {
        const source = MessageTray.getSystemSource();
        const notification = new MessageTray.Notification({
            source,
            title,
            body,
            isTransient: true,
            forFeedback: true,
        });
        notification.addAction(_('Undo'), () => undoCallback());
        source.addNotification(notification);
    }
}

var appFavoritesInstance = null;

/**
 * @returns {AppFavorites}
 */
export function getAppFavorites() {
    if (appFavoritesInstance == null)
        appFavoritesInstance = new AppFavorites();
    return appFavoritesInstance;
}
