import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import St from 'gi://St';
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';

import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';

const BUS_NAME = 'org.debsoftware.Indicator';
const OBJECT_PATH = '/org/debsoftware/Indicator';
const IFACE = `
<node>
  <interface name="org.debsoftware.Indicator">
    <method name="GetStatus">
      <arg type="i" direction="out"/>
      <arg type="s" direction="out"/>
    </method>
    <signal name="StatusChanged">
      <arg type="i"/>
      <arg type="s"/>
    </signal>
  </interface>
</node>
`;

const IndicatorNode = Gio.DBusNodeInfo.new_for_xml(IFACE);
const IndicatorIface = IndicatorNode.interfaces[0];

const Indicator = GObject.registerClass(
class Indicator extends PanelMenu.Button {
    _init() {
        super._init(0.0, _('Debian Software Manager'));

        this.add_style_class_name('panel-button');

        this._icon = new St.Icon({
            icon_name: 'update-none-symbolic',
            style_class: 'system-status-icon',
        });
        this.add_child(this._icon);

        this._proxy = new Gio.DBusProxy({
            g_connection: Gio.DBus.session,
            g_name: BUS_NAME,
            g_object_path: OBJECT_PATH,
            g_interface_name: 'org.debsoftware.Indicator',
            g_interface_info: IndicatorIface,
        });

        this._proxy.init_async(GLib.PRIORITY_DEFAULT, null, (proxy, result) => {
            try {
                proxy.init_finish(result);
                this._updateFromGetStatus();
            } catch (e) {
                logError(e, 'deb-software-indicator: Proxy init failed');
                this._updateIcon(0, 'low'); // Fallback
            }
        });

        this._signalId = Gio.DBus.session.signal_subscribe(
            BUS_NAME,
            'org.debsoftware.Indicator',
            'StatusChanged',
            OBJECT_PATH,
            null,
            Gio.DBusSignalFlags.NONE,
            this._onStatusChanged.bind(this)
        );

        this.connect('button-press-event', () => {
            Gio.Subprocess.new(
                ['/usr/bin/deb-software', '-u'],
                Gio.SubprocessFlags.NONE
            );
            return Clutter.EVENT_STOP;
        });

    }

    _updateFromGetStatus() {
        this._proxy.call(
            'GetStatus',
            null,
            Gio.DBusCallFlags.NONE,
            -1,
            null,
            (proxy, res) => {
                try {
                    let [count, urgency] = proxy.call_finish(res).deep_unpack();
                    this._updateIcon(count, urgency);
                } catch (e) {
                    logError(e, 'deb-software-indicator: GetStatus failed');
                }
            }
        );
    }

    _onStatusChanged(conn, sender, path, iface, signal, params) {
        try {
            let [count, urgency] = params.deep_unpack();
            this._updateIcon(count, urgency);
        } catch (e) {
            logError(e, 'deb-software-indicator: StatusChanged unpack failed');
        }
    }

    _updateIcon(count, urgency) {
        log(`deb-software-indicator: updating icon → count=${count}, urgency=${urgency}`);

        let icon;

        if (count === 0) {
            icon = 'update-none-symbolic';
        } else if (urgency === 'high') {
            icon = 'update-high-symbolic';
        } else {
            icon = 'update-low-symbolic';
        }

        this._icon.icon_name = icon;
    }

    destroy() {
        if (this._signalId) {
            Gio.DBus.session.signal_unsubscribe(this._signalId);
            this._signalId = 0;
        }
        super.destroy();
    }
});

export default class IndicatorExampleExtension extends Extension {
    enable() {
        this._indicator = new Indicator();
        Main.panel.addToStatusArea(this.uuid, this._indicator, 1, 'right');
    }

    disable() {
        if (this._indicator) {
            this._indicator.destroy();
            this._indicator = null;
        }
    }
}
