'''
Created on 23 janv. 2026

@author: denis
'''
import json
from threading import Thread, Event
from celery import Task
from celery.exceptions import Ignore
from celery.utils.log import get_task_logger
from redis import Redis
from django.conf import settings
from modules.mqttc import MqttBase as MqttClient


RELAY_SUB_TOPIC = "relay/+/#"
ZIGBEE_SUB_TOPIC = "zigbee2mqtt/#"


class Mqttc:
    task = None
    conf = dict(
        host=settings.MQTT_HOST,
        port=settings.MQTT_PORT,
        username=settings.MQTT_USERNAME,
        password=settings.MQTT_PASSWORD,
        ca_cert=settings.MQTT_CA_CERT,
        keepalive=60,
        topic_base=f"{settings.MQTT_ORIGINE}",
        topic_subs=[
            [RELAY_SUB_TOPIC, 0],
            #[ZIGBEE_SUB_TOPIC, 0],
        ]
    )


logger = get_task_logger(__name__)
redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0, decode_responses=True)
mqttc = Mqttc()


class MqttProcess(Task):

    def __init__(self):
        super().__init__()
        self.stop_event = Event()
        self.mqtt = MqttClient(on_messages=self._on_mqtt_message, **mqttc.conf)


    def __call__(self, *args, **kwargs):
        return self.start(*args, **kwargs)


    def start(self, *args, **kwargs):
        try:
            self.mqtt.startMQTT()
            self.start_redis_subscriber()
        except Exception as e:
            logger.error(e)
            raise Ignore()


    def stop(self):
        try:
            self.stop_event.set()
            self.mqtt.stopMQTT()
            logger.info(f"Listening stop.")
        except Exception as e:
            logger.error(e)


    def start_redis_subscriber(self):
        self.redis_subscriber = Thread(target=self._listen_to_redis, daemon=True)
        self.redis_subscriber.start()


    def _on_mqtt_message(self, topic, payload):
        try:
            #logger.info(f"---- on_mqtt_message {topic}: {payload}")
            if topic.startswith(RELAY_SUB_TOPIC[:-3]):
                uuid = topic.split('/')[1]
                redis.publish(f'relay_{uuid}', json.dumps({"type": "mqtt", "topic": topic, "payload":  payload}))
            else:
                redis.publish('mqtt_message', json.dumps({"type": "mqtt", "topic": topic, "payload":  payload}))

        except Exception as e:
            logger.error(f'on_mqtt_message: {e}')
            logger.error(topic)
            logger.error(payload)

    def _listen_to_redis(self):
        try:
            pubsub = redis.pubsub()
            pubsub.subscribe(f"mqtt_pub")
            logger.info(f"---- listen mqtt_message via redis")

            for message in pubsub.listen():
                if self.stop_event.is_set():
                    break
                data = json.loads(str(message.get('data')))
                if not isinstance(data, dict):
                    continue

                if data.get("type") == "mqtt":
                    self.mqtt._publish_message(data["topic"], **data["payload"])
        finally:
            pubsub.unsubscribe()
            pubsub.close()

