# message_bar.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
import gettext
from datetime import datetime, timezone

import gtk_meshtastic_client.utils as utils
import gtk_meshtastic_client.message_row as message_row
import gtk_meshtastic_client.utils as utils
import meshtastic
from meshtastic import BROADCAST_NUM
from meshtastic import mesh_pb2
from meshtastic.protobuf import portnums_pb2
import json
import os

@Gtk.Template(resource_path='/org/kop316/meshtastic/ui/message_bar.ui')
class MessageBar(Gtk.Box):
    __gtype_name__ = 'MessageBar'

    message_input = Gtk.Template.Child()
    message_buffer = Gtk.Template.Child()
    send_message_button = Gtk.Template.Child()
    message_buffer = Gtk.Template.Child()
    send_address = meshtastic.BROADCAST_NUM

    index = -1
    # "MA==" is the default, indicating there is no public key
    # It is the base64 equivalent of Hex 0x00
    publicKey = "MA=="

    def set_send_address(self, send_address):
        self.send_address = send_address

    def set_interface(self, interface):
        self.interface = interface

    def set_channel_index(self, index):
        self.index = index

    def set_nav_page(self, nav_page):
        self.nav_page = nav_page

    def set_channel_id(self, channel_id):
        self.channel_id = channel_id

    def set_public_key(self, publicKey):
        if not publicKey:
            self.logger.warning("publickey is NULL! This is a programming Error")
            return
        elif publicKey == "":
            self.logger.warning("publickey is empty! This is a programming Error")
            return
        self.publicKey = publicKey

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

        pki_encrypted = False

        if self.index == -1 and self.send_address == meshtastic.BROADCAST_NUM:
            self.logger.warning("Cannot send message, index not defined!")
            return

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

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

        text = self.message_buffer.get_text(self.message_buffer.get_start_iter(),
                                            self.message_buffer.get_end_iter(),
                                            False)

        if len(text) == 0:
            self.logger.debug("text empty")
            self.message_input.error_bell()
            return

        if len(text) > mesh_pb2.Constants.DATA_PAYLOAD_LEN:
            self.logger.debug("Length: " + str(len(text)) + " is too long!")
            app = Gtk.Application.get_default()
            win = Gtk.Application.get_active_window(app)
            dialog = Adw.AlertDialog.new(_("Alert"),
                                         _("Length: " + str(len(text)) + " is too long! "
                                           "Max Length is " + str(mesh_pb2.Constants.DATA_PAYLOAD_LEN) + "."))
            dialog.add_response ("close",  _("_Close"))

            dialog.present (win)
            return

        self.message_buffer.delete(self.message_buffer.get_start_iter(), self.message_buffer.get_end_iter())
        if self.send_address == meshtastic.BROADCAST_NUM:
            packet = self.interface.sendText(text=text, wantAck=True, channelIndex=self.index)
        elif self.publicKey == "MA==":
            packet = self.interface.sendText(text=text, wantAck=True, destinationId=self.send_address)
        else:
            packet = self.interface.sendData(data=text.encode("utf-8"),
                                             destinationId=self.send_address,
                                             portNum = portnums_pb2.PortNum.TEXT_MESSAGE_APP,
                                             pkiEncrypted=True,
                                             wantAck=True,
                                             channelIndex = 0)
            pki_encrypted = True

        if app.app_settings.get_log_packets():
            if os.path.exists(utils.messages_file_path):
                #FIXME: This doesn't seem to actually dump the packet into a JSON file, but I am not sure how that is done
                json_packet = json.dumps(packet, indent=4, default=lambda s: " ".join(str(s).split()))
                with open(utils.messages_file_path, 'r+') as json_file:
                    content = json_file.read().strip()
                    if content:
                        if content.endswith(']'):
                            content = content[:-1].rstrip() + ',\n'
                        else:
                            content = '['
                        json_file.seek(0)
                        json_file.write(content + json_packet + '\n]')
                    else:
                        json_file.seek(0)
                        json_file.write('[' + json_packet + '\n]')
                    json_file.truncate()
            else:
                with open(utils.messages_file_path, 'w') as json_file:
                    json_file.write('[\n' + json_packet + '\n]')

        if app.app_settings.get_print_packets():
            print(f"{packet} \n\n")

        chat_row = message_row.MessageRow()
        chat_row.set_message_direction(utils.MsgDirection.Out.value)
        """ This packet is not subscriptable, so you need to do getattr()"""
        chat_row.set_message_id(getattr(packet,"id"))
        unix_timestamp = int(datetime.now(timezone.utc).timestamp())
        chat_row.set_date(unix_timestamp)
        chat_row.set_message_content(text)
        chat_row.channel = self.index

        if self.send_address == meshtastic.BROADCAST_NUM:
            chat_row.set_direct_message(False)
        else:
            chat_row.set_direct_message(True)

        chat_row.update_pki_encryption(pki_encrypted)



        self.nav_page.add_message(chat_row)

        short_name = win.nearby_nodes_page_bin.own_node.shortName
        long_name = win.nearby_nodes_page_bin.own_node.longName
        from_id = win.nearby_nodes_page_bin.own_node.num
        win.connection_page_bin.database.add_sent_message_to_database(packet, self.interface, from_id, short_name, long_name, unix_timestamp, self.send_address, text, self.channel_id, pki_encrypted)

    """self doesn't seen to work, but widget is the correct widget for self"""
    def on_entry_activate(self, widget, action_name, param):
        app = Gtk.Application.get_default()

        if app.app_settings.get_return_sends_message():
            widget._message_bar_send_message_button_clicked_cb(widget.send_message_button)
        else:
            widget.message_buffer.insert_at_cursor ("\n", len("\n"))

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

        self.install_action("message-bar.activate", None, self.on_entry_activate)
        self.logger = app.logger
