"""MQTT client for activation trigger."""

import ssl
import threading
import time

from paho.mqtt import client as mqtt
from paho.mqtt.enums import CallbackAPIVersion
from rich.console import Console


console = Console()


class MQTTActivator:
    """MQTT client that triggers recording on specific topic."""

    def __init__(self, host="localhost", port=1883, topic="voicemqtt/activate",
                 timeout=5.0, username=None, password=None, use_tls=False,
                 tls_ca_certs=None, tls_certfile=None, tls_keyfile=None):
        """Initialize MQTT activator.

        Args:
            host: MQTT broker host
            port: MQTT broker port
            topic: Topic to listen for activation
            timeout: Connection timeout in seconds
            username: MQTT username for authentication (optional)
            password: MQTT password for authentication (optional)
            use_tls: Enable TLS/SSL encryption (default: False)
            tls_ca_certs: Path to CA certificates file (optional)
            tls_certfile: Path to client certificate file (optional)
            tls_keyfile: Path to client private key file (optional)
        """
        self.host = host
        self.port = port
        self.topic = topic
        self.timeout = timeout
        self.username = username
        self.password = password
        self.use_tls = use_tls
        self.tls_ca_certs = tls_ca_certs
        self.tls_certfile = tls_certfile
        self.tls_keyfile = tls_keyfile

        self.client = mqtt.Client(CallbackAPIVersion.VERSION2)
        self.client.on_connect = self._on_connect
        self.client.on_message = self._on_message
        self.client.on_disconnect = self._on_disconnect
        self.activated = False
        self.connected = False
        self._stop_event = threading.Event()

        if self.username and self.password:
            self.client.username_pw_set(self.username, self.password)

        if self.use_tls:
            self._setup_tls()

    def _setup_tls(self):
        """Configure TLS/SSL for MQTT connection."""
        try:
            if self.tls_ca_certs:
                self.client.tls_set(
                    ca_certs=self.tls_ca_certs,
                    certfile=self.tls_certfile,
                    keyfile=self.tls_keyfile,
                    cert_reqs=ssl.CERT_REQUIRED,
                    tls_version=ssl.PROTOCOL_TLS_CLIENT
                )
            else:
                self.client.tls_set(
                    cert_reqs=ssl.CERT_REQUIRED,
                    tls_version=ssl.PROTOCOL_TLS_CLIENT
                )
            console.print("[dim]TLS/SSL enabled[/dim]")
        except Exception as e:
            console.print(f"[red]Error setting up TLS: {e}[/red]")
            raise

    def _on_connect(self, client, userdata, flags, rc, properties=None):
        """Callback when connected to broker."""
        if rc == 0:
            self.connected = True
            client.subscribe(self.topic)
            console.print(f"[green]Connected to MQTT broker at {self.host}:{self.port}[/green]")
            console.print(f"[dim]Listening on topic: {self.topic}[/dim]")
        else:
            console.print(f"[red]Failed to connect to MQTT broker, return code: {rc}[/red]")
            
    def _on_disconnect(self, client, userdata, rc_or_flags, reason_code=None, properties=None):
        """Callback when disconnected from broker."""
        self.connected = False
        if reason_code is not None:
            rc = reason_code
        else:
            rc = rc_or_flags
        if isinstance(rc, int) and rc != 0:
            console.print(f"[yellow]Unexpectedly disconnected from MQTT broker (rc={rc})[/yellow]")
            
    def _on_message(self, client, userdata, msg):
        """Callback when message received."""
        payload = msg.payload.decode("utf-8").strip().lower()
        console.print(f"[dim]Received message on {msg.topic}: {payload}[/dim]")
        
        if payload in ("record", "start", "on", "1", "true", "yes"):
            console.print("[bold green]Activation triggered![/bold green]")
            self.activated = True
            
    def connect(self):
        """Connect to MQTT broker.
        
        Returns:
            bool: True if connected successfully
        """
        try:
            self.client.connect(self.host, self.port, 60)
            self.client.loop_start()
            
            start_time = time.time()
            while not self.connected and time.time() - start_time < self.timeout:
                time.sleep(0.1)
                
            return self.connected
        except Exception as e:
            console.print(f"[red]Error connecting to MQTT broker: {e}[/red]")
            return False
            
    def wait_for_activation(self):
        """Block until activation message received.
        
        Returns:
            bool: True if activated
        """
        console.print("[cyan]Waiting for activation message...[/cyan]")
        while not self._stop_event.is_set():
            if self.activated:
                self.activated = False
                return True
            time.sleep(0.1)
        return False
        
    def is_activated(self):
        """Check if activation was triggered.
        
        Returns:
            bool: True if activated (resets after check)
        """
        if self.activated:
            self.activated = False
            return True
        return False
        
    def publish(self, topic, payload, qos=0, retain=False):
        """Publish a message to an MQTT topic.

        Args:
            topic: Topic to publish to
            payload: Message payload (string or bytes)
            qos: Quality of Service level (0, 1, or 2)
            retain: Whether to retain the message

        Returns:
            bool: True if published successfully
        """
        try:
            if not self.connected:
                console.print("[red]Cannot publish: not connected to MQTT broker[/red]")
                return False
            result = self.client.publish(topic, payload, qos=qos, retain=retain)
            if result.rc == 0:
                return True
            else:
                console.print(f"[red]Failed to publish to {topic}, return code: {result.rc}[/red]")
                return False
        except Exception as e:
            console.print(f"[red]Error publishing to {topic}: {e}[/red]")
            return False

    def disconnect(self):
        """Disconnect from MQTT broker."""
        self._stop_event.set()
        self.client.loop_stop()
        self.client.disconnect()
        console.print("[dim]Disconnected from MQTT broker[/dim]")
