#!/usr/bin/env python3
import dbus
import dbus.mainloop.glib
from gi.repository import AppIndicator3
from gi.repository import Gtk, GLib, GObject
import gi
import subprocess
import threading
import time
import sys

# Especificar las versiones antes de importar
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')


class NetworkMenu:
    def __init__(self):
        self.app = 'network-menu'
        # Define el icono inicial
        self.indicator = AppIndicator3.Indicator.new(
            self.app,
            "/home/teraflops/Icons/wifi_disconnected.png",
            AppIndicator3.IndicatorCategory.SYSTEM_SERVICES
        )
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)

        self.menu = Gtk.Menu()
        self.build_menu()

        self.indicator.set_menu(self.menu)

        # Inicializar D-Bus
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        self.bus = dbus.SystemBus()

        try:
            self.network_manager = self.bus.get_object(
                'org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager')
            self.network_manager_props = dbus.Interface(
                self.network_manager, 'org.freedesktop.DBus.Properties')
        except dbus.exceptions.DBusException as e:
            print(
                f"Error al conectar con NetworkManager a través de D-Bus: {e}", file=sys.stderr)
            sys.exit(1)

        # Suscribirse a las señales de cambio de propiedades
        self.bus.add_signal_receiver(
            self.on_properties_changed,
            dbus_interface='org.freedesktop.DBus.Properties',
            signal_name='PropertiesChanged',
            arg0='org.freedesktop.NetworkManager',
            path='/org/freedesktop/NetworkManager',
        )

        # Obtener estado inicial
        self.update_status_initial()

    def build_menu(self):
        # Botón Conectar WiFi
        self.item_connect = Gtk.MenuItem(label='Conectar WiFi')
        self.item_connect.connect('activate', self.connect_wifi)
        self.menu.append(self.item_connect)

        # Botón Desconectar WiFi
        self.item_disconnect = Gtk.MenuItem(label='Desconectar WiFi')
        self.item_disconnect.connect('activate', self.disconnect_wifi)
        self.menu.append(self.item_disconnect)

        # Botón Ver Redes Disponibles
        self.item_view_networks = Gtk.MenuItem(label='Ver Redes Disponibles')
        self.item_view_networks.connect('activate', self.show_network_list)
        self.menu.append(self.item_view_networks)

        # Separador
        self.menu.append(Gtk.SeparatorMenuItem())

        # Botón Salir
        item_quit = Gtk.MenuItem(label='Salir')
        item_quit.connect('activate', self.quit)
        self.menu.append(item_quit)

        self.menu.show_all()

    def show_network_list(self, _):
        # Llamar a la función para obtener la lista de redes
        networks = self.get_available_networks_list()
        # Crear la ventana de lista de redes
        window = Gtk.Window(title="Redes Disponibles")
        window.set_default_size(300, 200)
        window.set_border_width(10)

        # Crear una caja vertical para la lista de redes y el botón de cerrar
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)

        # Añadir botones para cada red disponible
        for network in networks:
            button = Gtk.Button(label=network)
            button.connect(
                "clicked", self.prompt_password_and_connect, network)
            vbox.pack_start(button, True, True, 0)

        # Añadir un botón para cerrar la ventana
        close_button = Gtk.Button(label="Cerrar")
        close_button.connect("clicked", lambda x: window.destroy())
        vbox.pack_start(close_button, False, False, 0)

        window.add(vbox)
        window.show_all()

    def prompt_password_and_connect(self, button, network):
        # Crear un diálogo para solicitar la contraseña
        dialog = Gtk.Dialog(
            title=f"Conectar a {network}",
            transient_for=button.get_toplevel(),
            flags=0
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OK, Gtk.ResponseType.OK
        )

        # Crear un campo de entrada de texto para la contraseña
        box = dialog.get_content_area()
        label = Gtk.Label(label="Introduce la contraseña:")
        box.add(label)

        password_entry = Gtk.Entry()
        # Ocultar la contraseña al escribir
        password_entry.set_visibility(False)
        box.add(password_entry)
        dialog.show_all()

        # Ejecutar el diálogo y obtener la respuesta del usuario
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            password = password_entry.get_text()
            print(f"Intentando conectar a la red: {
                  network} con la contraseña ingresada.")
            # Llamar a nmcli con la contraseña
            subprocess.run(['nmcli', 'device', 'wifi',
                           'connect', network, 'password', password])
            self.show_notification(f"Intentando conectar a {network}")
        else:
            print("Conexión cancelada por el usuario.")

        dialog.destroy()

    def quit(self, _):
        Gtk.main_quit()

    def connect_wifi(self, _):
        ssid = self.get_available_ssid()
        if ssid:
            print(f"Conectando a {ssid}")
            subprocess.run(['nmcli', 'device', 'wifi', 'connect', ssid])
            self.show_notification(f"Conectando a {ssid}...")
        else:
            print("No se encontraron redes WiFi disponibles.")
            self.show_notification("No se encontraron redes WiFi disponibles.")

    def disconnect_wifi(self, _):
        print("Desconectando WiFi...")
        subprocess.run(['nmcli', 'radio', 'wifi', 'off'])
        self.show_notification("WiFi Desconectado.")

    def get_available_ssid(self):
        try:
            output = subprocess.getoutput(
                'nmcli -t -f SSID,SECURITY dev wifi list')
            print(f"Redes WiFi disponibles:\n{output}")
            networks = [line.split(':')[0]
                        for line in output.split('\n') if line]
            networks = list(dict.fromkeys(filter(None, networks)))
            print(f"SSIDs filtrados: {networks}")
            if networks:
                return networks[0]
            return None
        except Exception as e:
            print(f"Error al obtener SSID disponibles: {e}", file=sys.stderr)
            return None

    def get_available_networks_list(self):
        try:
            output = subprocess.getoutput(
                'nmcli -t -f SSID,SECURITY dev wifi list')
            networks = [line.split(':')[0]
                        for line in output.split('\n') if line]
            return list(dict.fromkeys(filter(None, networks)))
        except Exception as e:
            print(f"Error al obtener la lista de redes disponibles: {
                  e}", file=sys.stderr)
            return ["Error al obtener redes"]

    def show_notification(self, message):
        subprocess.run(['notify-send', message])

    def update_status_initial(self):
        try:
            wifi_state = self.get_wifi_state()
            ssid = self.get_connected_ssid()
            self.set_indicator(wifi_state, ssid)
        except dbus.exceptions.DBusException as e:
            print(f"Error al obtener el estado inicial: {e}", file=sys.stderr)

    def on_properties_changed(self, interface, changed_properties, invalidated_properties):
        if 'State' in changed_properties:
            wifi_state = self.get_wifi_state()
            ssid = self.get_connected_ssid()
            self.set_indicator(wifi_state, ssid)

    def set_indicator(self, wifi_state, ssid):
        if wifi_state == 'disabled':
            icon = "/home/teraflops/Icons/wifi_disabled.png"
            tooltip = "WiFi Apagado"
        elif wifi_state == 'enabled' and not ssid:
            icon = "/home/teraflops/Icons/wifi_disconnected.png"
            tooltip = "WiFi Encendido (No Conectado)"
        elif wifi_state == 'enabled' and ssid:
            icon = "/home/teraflops/Icons/wifi_enabled.png"
            tooltip = f"Conectado a: {ssid}"
        else:
            icon = "/home/teraflops/Icons/wifi_unknown.png"
            tooltip = "WiFi Estado Desconocido"

        print(f"Actualizando indicador: Icono={icon}, Tooltip='{tooltip}'")
        self.indicator.set_icon_full(icon, tooltip)
        self.indicator.set_title(tooltip)
        self.indicator.set_secondary_activate_target(None)

    def get_wifi_state(self):
        try:
            output = subprocess.getoutput("nmcli radio wifi")
            print(f"Estado WiFi: {output}")
            return output.lower()
        except Exception as e:
            print(f"Error al obtener el estado de WiFi: {e}", file=sys.stderr)
            return "unknown"

    def get_connected_ssid(self):
        try:
            # Usar iwgetid para obtener el SSID conectado
            ssid = subprocess.getoutput("iwgetid -r").strip()
            if ssid:
                print(f"SSID conectado obtenido con iwgetid: {ssid}")
                return ssid
            else:
                # Fallback a nmcli si iwgetid no retorna SSID
                output = subprocess.getoutput(
                    "nmcli -t -f ACTIVE,SSID dev wifi | grep '^yes' | cut -d':' -f2").strip()
                if output:
                    print(f"SSID conectado obtenido con nmcli: {output}")
                    return output
                else:
                    print(f"SSID conectado obtenido: None")
                    return None
        except Exception as e:
            print(f"Error al obtener SSID conectado: {e}", file=sys.stderr)
            return None


def main():
    NetworkMenu()
    Gtk.main()


if __name__ == "__main__":
    main()
