#!/usr/bin/env python3
import importlib.util
import logging
import logging.handlers
import os
import signal
import sys

import dbus.mainloop.glib

import daemon
import daemon.pidfile
from gi.repository import GLib
from i3notifier.data_manager import DataManager
from i3notifier.notification_fetcher import NotificationFetcher
from i3notifier.rofi_gui import RofiGUI


def get_user_config():

    config_path = os.path.join(
        os.environ["XDG_CONFIG_HOME"]
        if "XDG_CONFIG_HOME" in os.environ
        else os.path.join(os.environ["HOME"], ".config"),
        "i3",
        "i3_notifier_config.py",
    )

    if os.path.exists(config_path):
        logger.info(f"Loading user config from {config_path}")
        spec = importlib.util.spec_from_file_location("i3_notifier_config", config_path)
        userconfig = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(userconfig)
        return userconfig
    logger.info(f"File not found: {config_path}")


def run_daemon():
    config_list = []
    userconfig = get_user_config()
    if userconfig is not None:
        config_list = userconfig.config_list

    logger.info(f"Found {len(config_list)} configurations.")

    dump_path = os.path.join("/tmp", os.environ["USER"], "i3-notifier.dump")
    logger.info(
        f"Notifications will be dumped to {dump_path} on graceful exit or when asked."
    )
    data_manager = DataManager(config_list, dump_path)

    gui = RofiGUI()

    def dump_and_exit(n, f):
        data_manager.dump()
        sys.exit(0)

    pid_file = os.path.join("/tmp", os.environ["USER"], "i3-notifier.pid")

    if os.path.exists(pid_file):
        try:
            pid = int(open(pid_file).read().strip())
            os.kill(pid, 0)
            logger.info(f"i3-notifier is already running with pid {pid}.")
        except:
            os.remove(pid_file)
            logger.info(
                "i3-notifier is not running, but a lock file exists. Cleaning up."
            )

    with daemon.DaemonContext(
        pidfile=daemon.pidfile.PIDLockFile(pid_file),
        signal_map={signal.SIGTERM: dump_and_exit},
        files_preserve=[file_logger.stream.fileno()],
    ):
        logger.info(f"Creating lock file {pid_file}")
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        fetcher = NotificationFetcher(data_manager, gui)

        logger.info(f"Starting i3-notifier.")
        try:
            GLib.MainLoop().run()
        except:
            logger.info("Exiting Glib.MainLoop")
            data_manager.dump()


if __name__ == "__main__":

    logger = logging.getLogger("i3notifier")
    file_logger = logging.FileHandler(
        f"/tmp/{os.environ['USER']}/i3-notifier.log", "w",
    )
    file_logger.setFormatter(
        logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    )
    logger.addHandler(file_logger)
    logger.setLevel(logging.INFO)

    run_daemon()
