import time
import RNS

from kivy.metrics import dp,sp
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, BooleanProperty
from kivymd.uix.list import MDList, IconLeftWidget, IconRightWidget, TwoLineAvatarIconListItem
from kivymd.uix.menu import MDDropdownMenu
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.core.clipboard import Clipboard

from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.dialog import MDDialog

from kivy.lang.builder import Builder

from kivy.utils import escape_markup
if RNS.vendor.platformutils.get_platform() == "android":
    from ui.helpers import multilingual_markup, sig_icon_for_q
else:
    from .helpers import multilingual_markup, sig_icon_for_q

if RNS.vendor.platformutils.get_platform() == "android":
    from ui.helpers import ts_format
else:
    from .helpers import ts_format

class Announces():
    def __init__(self, app):
        self.app = app
        self.context_dests = []
        self.added_item_dests = []
        self.list = None

        if not self.app.root.ids.screen_manager.has_screen("announces_screen"):
            self.screen = Builder.load_string(layout_announces_screen)
            self.screen.app = self.app
            self.ids = self.screen.ids
            self.app.root.ids.screen_manager.add_widget(self.screen)

        self.fetch_announces()
        self.list = MDList()
        # self.update()

    def fetch_announces(self):
        self.announces = self.app.sideband.list_announces()

    def reload(self):
        self.clear_list()
        self.update()

    def clear_list(self):
        if self.list != None:
            self.list.clear_widgets()

        self.context_dests = []
        self.added_item_dests = []

    def update(self):
        us = time.time()
        self.fetch_announces()
        self.update_widget()
        self.app.sideband.setstate("app.flags.new_announces", False)
        RNS.log("Updated announce stream widgets in "+RNS.prettytime(time.time()-us), RNS.LOG_DEBUG)

    def update_widget(self):
        if self.list == None:
            self.list = MDList()

        remove_widgets = []
        for item in self.list.children:
            if not item.sb_uid in (a["dest"] for a in self.announces):
                remove_widgets.append(item)
            
            else:
                for announce in self.announces:
                    if announce["dest"] == item.sb_uid:
                        if announce["time"] > item.ts:
                            remove_widgets.append(item)
                            break

        for item in remove_widgets:
            if item.sb_uid in self.added_item_dests:
                self.added_item_dests.remove(item.sb_uid)
            self.list.remove_widget(item)

        for announce in self.announces:
            context_dest = announce["dest"]
            ts = announce["time"]
            a_name = announce["name"]
            a_cost = announce["cost"]
            dest_type = announce["type"]
            a_rssi = None
            a_snr = None
            a_q = None

            link_extras_str = ""
            link_extras_full = ""
            if "extras" in announce and announce["extras"] != None:
                extras = announce["extras"]
                if "link_stats" in extras:
                    link_stats = extras["link_stats"]
                    if "rssi" in link_stats and "snr" in link_stats and "q" in link_stats:
                        a_rssi = link_stats["rssi"]
                        a_snr  = link_stats["snr"]
                        a_q    = link_stats["q"]
                        if a_rssi != None and a_snr != None and a_q != None:
                            link_extras_str  = f" ([b]RSSI[/b] {a_rssi} [b]SNR[/b] {a_snr})"
                            link_extras_full = f"\n[b]Link Quality[/b] {a_q}%[/b]\n[b]RSSI[/b] {a_rssi}\n[b]SNR[/b] {a_snr}"

            sig_icon = multilingual_markup(sig_icon_for_q(a_q).encode("utf-8")).decode("utf-8")

            if not context_dest in self.added_item_dests:
                if self.app.sideband.is_trusted(context_dest):
                    trust_icon = "account-check"
                else:
                    trust_icon = "account-question"

                def gen_info(ts, dest, name, cost, dtype, link_extras):
                    name = multilingual_markup(escape_markup(str(name)).encode("utf-8")).decode("utf-8")
                    cost = str(cost)
                    def x(sender):
                        yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18))    
                        if dtype == "lxmf.delivery":
                            ad_text = "[size=22dp]LXMF Peer[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+"\n[b]Name[/b] "+name+"\n[b]Stamp Cost[/b] "+cost+link_extras

                        if dtype == "lxmf.propagation":
                            ad_text = "[size=22dp]LXMF Propagation Node[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+link_extras

                        dialog = MDDialog(
                            text=ad_text,
                            buttons=[ yes_button ],
                            # elevation=0,
                        )
                        def dl_yes(s):
                            dialog.dismiss()

                        yes_button.bind(on_release=dl_yes)
                        item.dmenu.dismiss()
                        dialog.open()
                    return x

                time_string = sig_icon + "  " + time.strftime(ts_format, time.localtime(ts)) + link_extras_str
                time_string_plain = time.strftime(ts_format, time.localtime(ts))

                if dest_type == "lxmf.delivery":
                    disp_name = multilingual_markup(escape_markup(str(self.app.sideband.peer_display_name(context_dest))).encode("utf-8")).decode("utf-8")
                    iconl = IconLeftWidget(icon=trust_icon)

                elif dest_type == "lxmf.propagation":
                    disp_name = "Propagation Node "+RNS.prettyhexrep(context_dest)
                    iconl = IconLeftWidget(icon="upload-network")

                else:
                    disp_name = "Unknown Announce"
                    iconl = IconLeftWidget(icon="progress-question")

                item = TwoLineAvatarIconListItem(text=time_string, secondary_text=disp_name, on_release=gen_info(time_string_plain, context_dest, a_name, a_cost, dest_type, link_extras_full))
                item.add_widget(iconl)
                item.sb_uid = context_dest
                item.ts = ts

                def gen_del(dest, item):
                    def x():
                        yes_button = MDRectangleFlatButton(text="Yes",font_size=dp(18), theme_text_color="Custom", line_color=self.app.color_reject, text_color=self.app.color_reject)
                        no_button = MDRectangleFlatButton(text="No",font_size=dp(18))
                        dialog = MDDialog(
                            title="Delete announce?",
                            buttons=[ yes_button, no_button ],
                            padding=[0,0,dp(32),0]
                            # elevation=0,
                        )
                        def dl_yes(s):
                            dialog.dismiss()
                            def cb(dt):
                                self.app.sideband.delete_announce(dest)
                                self.update()
                            Clock.schedule_once(cb, 0.2)
                        def dl_no(s):
                            dialog.dismiss()

                        yes_button.bind(on_release=dl_yes)
                        no_button.bind(on_release=dl_no)
                        item.dmenu.dismiss()
                        dialog.open()
                    return x

                def gen_conv(dest, item):
                    def x():
                        item.dmenu.dismiss()
                        self.app.conversation_from_announce_action(dest)
                    return x

                def gen_copy_addr(dest, item):
                    def x():
                        Clipboard.copy(RNS.hexrep(dest, delimit=False))
                        item.dmenu.dismiss()
                    return x

                def gen_set_node(dest, item):
                    def x():
                        item.dmenu.dismiss()
                        self.app.sideband.set_active_propagation_node(dest)
                        self.app.sideband.config["lxmf_propagation_node"] = dest
                        self.app.sideband.save_configuration()
                    return x

                if dest_type == "lxmf.delivery":
                    dm_items = [
                        {
                            "viewclass": "OneLineListItem",
                            "text": "Converse",
                            "height": dp(40),
                            "on_release": gen_conv(context_dest, item)
                        },
                        {
                            "viewclass": "OneLineListItem",
                            "text": "Copy address",
                            "height": dp(40),
                            "on_release": gen_copy_addr(context_dest, item)
                        },
                        {
                            "text": "Delete Announce",
                            "viewclass": "OneLineListItem",
                            "height": dp(40),
                            "on_release": gen_del(context_dest, item)
                        }
                    ]

                elif dest_type == "lxmf.propagation":
                    dm_items = [
                        {
                            "viewclass": "OneLineListItem",
                            "text": "Use this Propagation Node",
                            "height": dp(40),
                            "on_release": gen_set_node(context_dest, item)
                        },
                        {
                            "viewclass": "OneLineListItem",
                            "text": "Copy address",
                            "height": dp(40),
                            "on_release": gen_copy_addr(context_dest, item)
                        },
                        {
                            "text": "Delete Announce",
                            "viewclass": "OneLineListItem",
                            "height": dp(40),
                            "on_release": gen_del(context_dest, item)
                        }
                    ]

                else:
                    dm_items = []

                item.iconr = IconRightWidget(icon="dots-vertical");
                
                item.dmenu = MDDropdownMenu(
                    caller=item.iconr,
                    items=dm_items,
                    position="auto",
                    width=dp(256),
                    elevation=0,
                    radius=dp(3),
                )
                item.dmenu.md_bg_color = self.app.color_hover

                def callback_factory(ref):
                    def x(sender):
                        ref.dmenu.open()
                    return x

                item.iconr.bind(on_release=callback_factory(item))
                item.add_widget(item.iconr)
                
                self.added_item_dests.append(context_dest)
                self.list.add_widget(item, index=len(self.list.children))

    def get_widget(self):
        return self.list

layout_announces_screen = """
MDScreen:
    name: "announces_screen"
    
    BoxLayout:
        orientation: "vertical"

        MDTopAppBar:
            title: "Announce Stream"
            anchor_title: "left"
            elevation: 0
            left_action_items:
                [['menu', lambda x: root.app.nav_drawer.set_state("open")]]
            right_action_items:
                [
                ['close', lambda x: root.app.close_settings_action(self)],
                ]
            #    [['eye-off', lambda x: root.ids.screen_manager.app.announce_filter_action(self)]]

        ScrollView:
            id: announces_scrollview

            MDBoxLayout:
                orientation: "vertical"
                spacing: "24dp"
                size_hint_y: None
                height: self.minimum_height
                padding: dp(64)

                MDLabel:
                    id: announces_info
                    markup: True
                    text: ""
                    size_hint_y: None
                    text_size: self.width, None
                    height: self.texture_size[1]
"""