import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import Pango from 'gi://Pango';
import Shell from 'gi://Shell';
import St from 'gi://St';

import * as Dialog from './dialog.js';
import * as ModalDialog from './modalDialog.js';
import * as PermissionStore from '../misc/permissionStore.js';

const APP_ALLOWLIST = ['org.gnome.Settings.desktop'];
const APP_PERMISSIONS_TABLE = 'gnome';
const APP_PERMISSIONS_ID = 'shortcuts-inhibitor';
const GRANTED = 'GRANTED';
const DENIED = 'DENIED';

const DialogResponse = Meta.InhibitShortcutsDialogResponse;

export const InhibitShortcutsDialog = GObject.registerClass({
    Implements: [Meta.InhibitShortcutsDialog],
    Properties: {
        'window': GObject.ParamSpec.override('window', Meta.InhibitShortcutsDialog),
    },
}, class InhibitShortcutsDialog extends GObject.Object {
    _init(window) {
        super._init();
        this._window = window;

        this._dialog = new ModalDialog.ModalDialog();
        this._buildLayout();
    }

    get window() {
        return this._window;
    }

    set window(window) {
        this._window = window;
    }

    get _app() {
        const windowTracker = Shell.WindowTracker.get_default();
        return windowTracker.get_window_app(this._window);
    }

    _shouldUsePermStore() {
        return this._app && !this._app.is_window_backed();
    }

    async _saveToPermissionStore(grant) {
        if (!this._shouldUsePermStore() || this._permStore == null)
            return;

        try {
            await this._permStore.SetPermissionAsync(APP_PERMISSIONS_TABLE,
                true,
                APP_PERMISSIONS_ID,
                this._app.get_id(),
                [grant]);
        } catch (error) {
            log(error.message);
        }
    }

    _buildLayout() {
        const name = this._app?.get_name() ?? this._window.title;

        const content = new Dialog.MessageDialogContent({
            title: _('Allow inhibiting shortcuts'),
            description: name
                /* Translators: %s is an application name like "Settings" */
                ? _('The app %s wants to inhibit shortcuts').format(name)
                : _('An app wants to inhibit shortcuts'),
        });

        const restoreAccel = Meta.prefs_get_keybinding_label('restore-shortcuts');
        if (restoreAccel) {
            const restoreLabel = new St.Label({
                /* Translators: %s is a keyboard shortcut like "Super+x" */
                text: _('You can restore shortcuts by pressing %s').format(restoreAccel),
                style_class: 'message-dialog-description',
            });
            restoreLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
            restoreLabel.clutter_text.line_wrap = true;
            content.add_child(restoreLabel);
        }

        this._dialog.contentLayout.add_child(content);

        this._dialog.addButton({
            label: _('Deny'),
            action: () => {
                this._saveToPermissionStore(DENIED);
                this._emitResponse(DialogResponse.DENY);
            },
            key: Clutter.KEY_Escape,
        });

        this._dialog.addButton({
            label: _('Allow'),
            action: () => {
                this._saveToPermissionStore(GRANTED);
                this._emitResponse(DialogResponse.ALLOW);
            },
            default: true,
        });
    }

    _emitResponse(response) {
        this.emit('response', response);
        this._dialog.close();
    }

    vfunc_show() {
        if (this._app && APP_ALLOWLIST.includes(this._app.get_id())) {
            this._emitResponse(DialogResponse.ALLOW);
            return;
        }

        if (!this._shouldUsePermStore()) {
            this._dialog.open();
            return;
        }

        /* Check with the permission store */
        const appId = this._app.get_id();
        this._permStore = new PermissionStore.PermissionStore(async (proxy, error) => {
            if (error) {
                log(error.message);
                this._dialog.open();
                return;
            }

            try {
                const [permissions] = await this._permStore.LookupAsync(
                    APP_PERMISSIONS_TABLE, APP_PERMISSIONS_ID);

                if (permissions[appId] === undefined) // Not found
                    this._dialog.open();
                else if (permissions[appId][0] === GRANTED)
                    this._emitResponse(DialogResponse.ALLOW);
                else
                    this._emitResponse(DialogResponse.DENY);
            } catch (err) {
                this._dialog.open();
                log(err.message);
            }
        });
    }

    vfunc_hide() {
        this._dialog.close();
    }
});
