#!/usr/bin/env python3

import json
import subprocess
import sys
from argparse import ArgumentParser
from datetime import datetime


def main(args):
    if args.current_user:
        print(json.dumps(get_current_user_units()))
        return 0

    for user in get_users():
        if not user_may_linger(user):
            continue
        for unit in get_user_units(user):
            if not unit["unit"].endswith(".service"):
                continue
            if "/.config/systemd/user/" not in unit["fragment_path"]:
                continue
            print(
                get_state(unit["active"]),
                '"%s:%s"' % (user, unit["unit"]),
                "-",
                "%s is %s since %s"
                % (
                    unit["unit"],
                    unit["active"],
                    format_timestamp(unit["state_change_timestamp"]),
                ),
            )

    return 0


def format_timestamp(timestamp):
    return datetime.fromtimestamp(timestamp / 1e6).isoformat()


def get_state(active_state):
    if active_state == "failed":
        return 2
    return 0


def get_users():
    return [
        u["user"]
        for u in json.loads(
            subprocess.check_output(
                [
                    "loginctl",
                    "list-users",
                    "--output",
                    "json",
                ]
            )
        )
    ]


def user_may_linger(user):
    return get_user_prop(user, "Linger") == "yes"


def get_user_units(user):
    return json.loads(run_as_user(user, [sys.executable, __file__, "--current-user"]))


def get_current_user_units():
    import dbus

    bus = dbus.SessionBus()
    systemd = bus.get_object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
    manager = dbus.Interface(systemd, "org.freedesktop.systemd1.Manager")

    result = []
    for (
        unit_name,
        _description,
        _load_state,
        active_state,
        _sub_state,
        _,
        obj_path,
        *_,
    ) in manager.ListUnits():
        props = dbus.Interface(
            bus.get_object("org.freedesktop.systemd1", obj_path),
            "org.freedesktop.DBus.Properties",
        )
        result.append(
            {
                "unit": unit_name,
                "active": active_state,
                "fragment_path": props.Get(
                    "org.freedesktop.systemd1.Unit", "FragmentPath"
                ),
                "state_change_timestamp": props.Get(
                    "org.freedesktop.systemd1.Unit", "StateChangeTimestamp"
                ),
            }
        )

    return result


def run_as_user(user, cmd):
    return subprocess.check_output(
        [
            "sudo",
            "-u",
            user,
            "env",
            "XDG_RUNTIME_DIR=%s" % get_user_prop(user, "RuntimePath"),
            *cmd,
        ],
        encoding="utf-8",
    )


def get_user_prop(user, prop):
    return subprocess.check_output(
        ["loginctl", "show-user", "--value", "-p", prop, user], encoding="utf-8"
    ).strip()


parser = ArgumentParser()
parser.add_argument("--current-user", action="store_true")

if __name__ == "__main__":
    sys.exit(main(parser.parse_args()))
