# bluetooth_device_row.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

from gi.repository import Adw
from gi.repository import Gtk
from gi.repository import Gio
from pubsub import pub
import gettext
import meshtastic.ble_interface

import gtk_meshtastic_client.utils as utils

@Gtk.Template(resource_path='/org/kop316/meshtastic/ui/bluetooth_device_row.ui')
class BluetoothDeviceRow(Adw.ActionRow):
    __gtype_name__ = 'BluetoothDeviceRow'

    connect_button = Gtk.Template.Child()
    favorite_button = Gtk.Template.Child()

    favorited = False

    def set_ble_database(self, ble_database):
        self.ble_database = ble_database

    def set_connection_page(self, connection_page):
        self.connection_page = connection_page

    def set_device_name(self, device_name):
        self.device_name = device_name
        self.set_title("Name: " + str(device_name))

    def ble_addr_str_to_int(self, addr, base):
        segments = list(reversed(addr.split(":")))
        result = 0
        for i in range(len(segments)):
            result += int(segments[i], base=base) * 256 ** i
        return result

    def set_device_address(self, device_address):
        self.device_address = device_address
        self.set_subtitle("Address: " + str(device_address))
        self.device_address_int = self.ble_addr_str_to_int(self.device_address, 16)

    def _bluetooth_connect_finish(self, self_object, result: Gio.AsyncResult):
        app = Gtk.Application.get_default()
        win = Gtk.Application.get_active_window(app)

        if not Gio.Task.is_valid(result, self_object):
            self.logger.warning("Not valid GTask")
            win.connection_page_bin.set_connected_button_sensitivity(False)
            win.window_toast_overlay.add_toast(Adw.Toast(title="Bluetooth Connection Failed"))
            return

        success = result.propagate_boolean()
        if not success:
            self.logger.warning("Connection failed!")
            win.connection_page_bin.set_connected_button_sensitivity(False)
            win.window_toast_overlay.add_toast(Adw.Toast(title="Bluetooth Connection Failed"))
            return

    def _bluetooth_connect_async(self, callback) -> None:
        def _bluetooth_connect(task, _source_object, _task_data, _cancellable):
            self.logger.debug("Start Bluetooth Connect")
            address_to_connect = self.device_address
            try:
                self.logger.debug("Connecting to bluetooth interface: " + address_to_connect)
                meshtastic.ble_interface.BLEInterface(address_to_connect)
            except:
                task.return_boolean(False)
                return

            task.return_boolean(True)

        task = Gio.Task.new(self, None, callback)
        task.run_in_thread(_bluetooth_connect)

    @Gtk.Template.Callback()
    def _bluetooth_connect_button_clicked_cb(self, button):
        app = Gtk.Application.get_default()
        win = Gtk.Application.get_active_window(app)

        if not self.connect_button.get_sensitive():
            self.logger.debug("Application not ready to connect")
            return

        if not self.device_address:
            self.logger.warning("cannot connect, BLE Address not known")
            return

        if not hasattr(self, 'connection_page'):
            self.logger.warning("Cannot send message, connection page not defined!")
            return

        win.connection_page_bin.ble_device_address = self.device_address
        pub.subscribe(self.connection_page.onConnection, 'meshtastic.connection.established')
        self._bluetooth_connect_async(callback=self._bluetooth_connect_finish)
        win.connection_page_bin.set_disconnect_button_sensitivity(False)

    def toggle_favorite_node(self, alter_database):
        app = Gtk.Application.get_default()
        win = Gtk.Application.get_active_window(app)
        """Removing a node from favorites"""
        if self.favorited:
            self.favorite_button.set_icon_name("non-starred-symbolic")
            self.favorited = False
            if alter_database:
                self.logger.debug("Removing BLE device from database")
                self.ble_database.remove_node_from_database(self.device_address)
            """ Adding a node from favorites """
        else:
            self.favorite_button.set_icon_name("starred-symbolic")
            self.favorited = True

            if alter_database:
                self.logger.debug("Adding BLE device to database")
                self.ble_database.add_node_to_database(self.device_name, self.device_address)

        self.connection_page.bluetooth_devices_list_box.invalidate_sort()

    @Gtk.Template.Callback()
    def _favorite_button_clicked_cb(self, button):
        self.toggle_favorite_node(True)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        app = Gtk.Application.get_default()
        self.logger = app.logger
