#!/usr/bin/python3
"""
Copyright (C) 2026 Shawn W Dunn

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

txnupd-notifier-client — Emit org.opensuse.tukit.Updated Notify signal.

Acquires org.opensuse.tukit.Updated on the D-Bus system bus and emits a
Notify signal with the given status.  Must run as root; the D-Bus policy
restricts ownership of this name to root.

Called by transactional-update(8) via the transactional-update-notifier
symlink when REBOOT_METHOD=notify is set.
"""

import logging
import sys

import dbus
import dbus.mainloop.glib
import dbus.service
from gi.repository import GLib


LOG = logging.getLogger("txnupd-notifier")

TUKIT_INTERFACE = "org.opensuse.tukit.Updated"
TUKIT_PATH      = "/org/opensuse/tukit/Updated"
TUKIT_MEMBER    = "Notify"


def run_client(status: str) -> None:
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    try:
        system_bus = dbus.SystemBus()
        bus_name = dbus.service.BusName(TUKIT_INTERFACE, system_bus)
    except dbus.DBusException:
        LOG.exception("Cannot acquire %s — must run as root", TUKIT_INTERFACE)
        sys.exit(1)

    class _Notifier(dbus.service.Object):
        @dbus.service.signal(dbus_interface=TUKIT_INTERFACE, signature="s")
        def Notify(self, status: str) -> None:
            pass

    notifier = _Notifier(bus_name, TUKIT_PATH)
    loop = GLib.MainLoop()

    def _emit_and_quit() -> bool:
        notifier.Notify(status)
        LOG.info("Emitted %s.%s: %s", TUKIT_INTERFACE, TUKIT_MEMBER, status)
        loop.quit()
        return False

    GLib.idle_add(_emit_and_quit)
    loop.run()


def main() -> None:
    logging.basicConfig(
        level=logging.INFO,
        format="%(name)s[%(process)d]: %(levelname)s %(message)s",
    )

    args = sys.argv[1:]
    # transactional-update(8) calls: transactional-update-notifier client
    # Strip the legacy "client" keyword so existing callers keep working.
    if args and args[0] == "client":
        args = args[1:]

    status = args[0] if args else "success"
    if status not in ("success", "failure"):
        print(f"Usage: {sys.argv[0]} [success|failure]", file=sys.stderr)
        sys.exit(1)

    run_client(status)


if __name__ == "__main__":
    main()
