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';

// In alphabetical order
const RENAMED_DESKTOP_IDS = {
    'baobab.desktop': 'org.gnome.baobab.desktop',
    'cheese.desktop': 'org.gnome.Cheese.desktop',
    'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
    'empathy.desktop': 'org.gnome.Empathy.desktop',
    'eog.desktop': 'org.gnome.eog.desktop',
    'epiphany.desktop': 'org.gnome.Epiphany.desktop',
    'evolution.desktop': 'org.gnome.Evolution.desktop',
    'file-roller.desktop': 'org.gnome.FileRoller.desktop',
    'five-or-more.desktop': 'org.gnome.five-or-more.desktop',
    'four-in-a-row.desktop': 'org.gnome.Four-in-a-row.desktop',
    'gcalctool.desktop': 'org.gnome.Calculator.desktop',
    'geary.desktop': 'org.gnome.Geary.desktop',
    'gedit.desktop': 'org.gnome.gedit.desktop',
    'glchess.desktop': 'org.gnome.Chess.desktop',
    'glines.desktop': 'org.gnome.five-or-more.desktop',
    'gnect.desktop': 'org.gnome.Four-in-a-row.desktop',
    'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
    'gnobots2.desktop': 'org.gnome.Robots.desktop',
    'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
    'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
    'gnome-chess.desktop': 'org.gnome.Chess.desktop',
    'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
    'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
    'gnome-documents.desktop': 'org.gnome.Documents.desktop',
    'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
    'gnome-klotski.desktop': 'org.gnome.Klotski.desktop',
    'gnome-nibbles.desktop': 'org.gnome.Nibbles.desktop',
    'gnome-mahjongg.desktop': 'org.gnome.Mahjongg.desktop',
    'gnome-mines.desktop': 'org.gnome.Mines.desktop',
    'gnome-music.desktop': 'org.gnome.Music.desktop',
    'gnome-photos.desktop': 'org.gnome.Photos.desktop',
    'gnome-robots.desktop': 'org.gnome.Robots.desktop',
    'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
    'gnome-software.desktop': 'org.gnome.Software.desktop',
    'gnome-terminal.desktop': 'org.gnome.Terminal.desktop',
    'gnome-tetravex.desktop': 'org.gnome.Tetravex.desktop',
    'gnome-tweaks.desktop': 'org.gnome.tweaks.desktop',
    'gnome-weather.desktop': 'org.gnome.Weather.desktop',
    'gnomine.desktop': 'org.gnome.Mines.desktop',
    'gnotravex.desktop': 'org.gnome.Tetravex.desktop',
    'gnotski.desktop': 'org.gnome.Klotski.desktop',
    'gtali.desktop': 'org.gnome.Tali.desktop',
    'iagno.desktop': 'org.gnome.Reversi.desktop',
    'nautilus.desktop': 'org.gnome.Nautilus.desktop',
    'org.gnome.gnome-2048.desktop': 'org.gnome.TwentyFortyEight.desktop',
    'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
    'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop',
    'polari.desktop': 'org.gnome.Polari.desktop',
    'seahorse.desktop': 'org.gnome.seahorse.Application.desktop',
    'shotwell.desktop': 'org.gnome.Shotwell.desktop',
    'simple-scan.desktop': 'org.gnome.SimpleScan.desktop',
    'tali.desktop': 'org.gnome.Tali.desktop',
    'totem.desktop': 'org.gnome.Totem.desktop',
    'evince.desktop': 'org.gnome.Evince.desktop',
};

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.reload();
            this.emit('changed');
        });

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

    _onFavsChanged() {
        this.reload();
        this.emit('changed');
    }

    reload() {
        let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
        let appSys = Shell.AppSystem.get_default();

        // Map old desktop file names to the current ones
        let updated = false;
        ids = ids.map(id => {
            let newId = RENAMED_DESKTOP_IDS[id];
            if (newId !== undefined &&
                appSys.lookup_app(newId) != null) {
                updated = true;
                return newId;
            }
            return id;
        });
        // ... and write back the updated desktop file names
        if (updated)
            global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);

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

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

    getFavoriteMap() {
        return this._favorites;
    }

    getFavorites() {
        let ret = [];
        for (let 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;

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

        if (!app)
            return false;

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

        let 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 has been pinned to the 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;

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

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

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

        this._showNotification(_('%s has been unpinned from the 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;
}
