import logging

from paho.mqtt.client import Client

from MQTTSubject import MQTTSubject

class MQTTClient(MQTTSubject):
    """
    MQTTClient class that extends the MQTTSubject class.
    This class is responsible for managing the MQTT client and its connection.
    """
    def __init__(self, host: str, port: int, username: str = None, password: str = None, crt_path: str = None) -> None:
        super().__init__()
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.crt_path = crt_path
        self.client: Client = Client()
        self.client.on_connect = self._on_connect
        self.MQTT_ADD_TOPIC = "telegram/add"
        self.MQTT_REMOVE_TOPIC = "telegram/remove"
        self.MQTT_PING_TOPIC = "telegram/ping"
        self.MQTT_PONG_TOPIC = "telegram/pong"
        self.MQTT_OK_TOPIC = "telegram/ok"


    
    def _on_connect(self, client: Client, userdata: None, flags: dict, rc: int) -> None:
        if rc == 0:
            logging.info("Connected to MQTT broker")
            client.subscribe(self.MQTT_ADD_TOPIC)
            client.subscribe(self.MQTT_REMOVE_TOPIC)
            client.subscribe(self.MQTT_PING_TOPIC)
        else:
            logging.error(f"Failed to connect to MQTT broker, return code {rc}")
            client.loop_stop()
            client.disconnect()
            exit(1)


    def connect(self) -> None:
        """
        Connects to the MQTT broker.

        Args:
            host (str): The hostname of the MQTT broker.
            port (int): The port number of the MQTT broker.
            username (str): The username for the MQTT broker. Default is None.
            password (str): The password for the MQTT broker. Default is None.
        """
        if self.username and self.password:
            self.client.username_pw_set(self.username, self.password)

        if self.crt_path:
            self.client.tls_set(ca_certs=self.crt_path)
            
        self.client.connect(self.host, self.port)
        self.client.loop_forever() 
        

    def set_on_message_callback(self, callback: callable) -> None:
        """
        Sets the callback function for when a message is received.

        Args:
            callback (callable): The callback function to be called when a message is received.
        """
        self.client.on_message = callback

    
    def subscribe(self, topic: str) -> None:
        """
        Subscribes to a topic.

        Args:
            topic (str): The topic to subscribe to.
        """
        self.client.subscribe(topic)
        logging.info(f"Subscribed to topic: {topic}")

    def publish(self, topic: str, payload: str) -> None:
        """
        Publishes a message to a topic.

        Args:
            topic (str): The topic to publish to.
            payload (str): The message payload.
        """
        self.client.publish(topic, payload)

    def unsubscribe(self, topic: str) -> None:
        """
        Unsubscribes from a topic.

        Args:
            topic (str): The topic to unsubscribe from.
        """
        self.client.unsubscribe(topic)