# main.py
#
# Copyright 2024 Christopher Talbot
#
# 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/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later

import signal
import sys
import gi
import gettext
import os
import gtk_meshtastic_client.utils as utils

gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
gi.require_version('Shumate', '1.0')

from gi.repository import Gtk, Gio, Adw, GObject, GLib
from gi.repository import Shumate
from .window import GtkMeshtasticClientWindow
#import faulthandler

import gtk_meshtastic_client.preferences_dialog as preferences_dialog
import gtk_meshtastic_client.settings as settings
import gtk_meshtastic_client.logger as logger

class GtkMeshtasticClientApplication(Adw.Application):
    """The main application singleton class."""
    app_debug = False

    def __init__(self, project_rdnn_name):
        super().__init__(application_id=project_rdnn_name,
                         flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.create_action('quit', lambda *_: self.quit_app(), ['<primary>q'])
        self.create_action('about', self.on_about_action)
        self.create_action('preferences', self.on_preferences_action)

        self.add_main_option(
            'debug',
            ord('d'),
            GLib.OptionFlags.NONE,
            GLib.OptionArg.NONE,
            'Show Debug Messages in Stdout',
            None,
        )

        self.add_main_option(
            'version',
            ord('v'),
            GLib.OptionFlags.NONE,
            GLib.OptionArg.NONE,
            'Display version & exit',
            None,
        )

    def do_activate(self):
        """Called when the application is activated.

        We raise the application's main window, creating it if
        necessary.
        """
        win = self.props.active_window
        if not win:
            win = GtkMeshtasticClientWindow(project_rdnn_name=self.project_rdnn_name, application=self)
        win.present()

    def do_startup(self):
        Adw.Application.do_startup(self)
        """Set up Config Directory"""
        if not os.path.exists(utils.meshtastic_config_dir):
            os.makedirs(utils.meshtastic_config_dir)

        self.logger = logger.LoggerObject(project_rdnn_name=self.project_rdnn_name)
        self.app_settings = settings.SettingsObject(project_rdnn_name=self.project_rdnn_name)
#        faulthandler.enable()

    def on_about_action(self, *args):
        """Callback for the app.about action."""
        about = Adw.AboutDialog(application_name=_("GTK Meshtastic Client"),
                                application_icon=self.project_rdnn_name,
                                artists=['alaraajavamma'],
                                developer_name='Chris Talbot',
                                version=self.program_version,
                                developers=['Chris Talbot'],
                                copyright=_("© 2024 Christopher Talbot\n\n"
                                          "Meshtastic and Meshtastic Logos are "
                                          "a Trademark of Meshtastic LLC, and "
                                          "they do not endorse or "
                                          "sponsor this project."),
                                website='https://gitlab.com/kop316/gtk-meshtastic-client',
                                issue_url='https://gitlab.com/kop316/gtk-meshtastic-client/-/issues',
                                support_url='https://gitlab.com/kop316/gtk-meshtastic-client/-/wikis/home',
                                license_type=Gtk.License.GPL_3_0)

        about.present(self.props.active_window)

    def on_preferences_action(self, widget, _):
        """Callback for the app.preferences action."""
        win = Gtk.Application.get_active_window(self)
        dialog = preferences_dialog.PreferencesDialog()
        dialog.present(win)

    def do_command_line(self, command_line):
        options = command_line.get_options_dict()
        # convert GVariantDict -> GVariant -> dict
        options = options.end().unpack()

        if 'version' in options:
            # This is printed on the main instance
            print("Version: " + str(self.program_version))
            self.quit()

        if 'debug' in options:
            GLib.log_set_debug_enabled(True)

        self.activate()
        return 0

    def create_action(self, name, callback, shortcuts=None):
        """Add an application action.

        Args:
            name: the name of the action
            callback: the function to be called when the action is
              activated
            shortcuts: an optional list of accelerators
        """
        action = Gio.SimpleAction.new(name, None)
        action.connect("activate", callback)
        self.add_action(action)
        if shortcuts:
            self.set_accels_for_action(f"app.{name}", shortcuts)

    def signal_timeout_cb(self) -> bool:
        app = Gtk.Application.get_default()
        app.quit()
        return GLib.SOURCE_REMOVE

    """
    You need to close any active connections if you exit
    If you don't, the interface will continue to be active
    and any stored messages will stay stored on the device
    and will be sent on the stale connection
    """
    def quit_app(self):
        app = Gtk.Application.get_default()
        win = Gtk.Application.get_active_window(app)

        win.quit_request = True
        app.logger.debug("Disconnecting Meshtastic Device before quitting")

        """
        We always want to gracefully disconnect the interface if we are quitting
        this program. If we don't, the interface is in an unknown state and we
        will miss messages while disconnected.
        """
        if hasattr(win.connection_page_bin, 'interface'):
            win.close()
            """
            If we get the signal to quit, we always quit the application. However,
            if get_quit_if_connected() is false, we have to manually disconnect
            the interface because closing the window won't disconnect the interface.
            Since win.quit_request is true, the application will quit.
            """
            if not app.app_settings.get_quit_if_connected():
                win.connection_page_bin._disconnect_button_clicked_cb(win.connection_page_bin.disconnect_button)
        else:
            app.quit()

        GLib.timeout_add(10000, self.signal_timeout_cb)

def signal_handler(sig, frame):
    app = Gtk.Application.get_default()
    app.logger.debug("Received Quit Signal")
    app.quit_app()

def main(version, project_rdnn_name, gettext_package, package_name):
    """The application's entry point."""
    app = GtkMeshtasticClientApplication(project_rdnn_name=project_rdnn_name)
    app.program_version = version
    app.project_rdnn_name = project_rdnn_name
    app.gettext_package = gettext_package
    app.package_name = package_name

    """
    Shumate doesn't provide an init() function
    https://gitlab.gnome.org/GNOME/libshumate/-/issues/64
    """
    GObject.type_ensure(Shumate.SimpleMap)


    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGQUIT, signal_handler)
    return app.run(sys.argv)
