from paho.mqtt.client import Client, MQTTMessage
from threading import Thread
import random
import os
import time
import json
import sys

if getattr(sys, 'frozen', False):
    ASSETS_DIR = os.path.join(sys._MEIPASS, "assets") 
else: 
    ASSETS_DIR = os.path.dirname(os.path.abspath(__file__)) + "/assets"

class ESP32Client:

    def __init__(self, ip, port, username, password, tls_cert):
        self._camera_id = self.generate_esp32_id()
        self._ip = ip
        self._port = port
        self._username = username
        self._password = password
        self._tls_cert = tls_cert
        self._PING_TOPIC = "esp32/ping" 
        self._PONG_TOPIC = "esp32/pong"
        self._IMAGE_TOPIC = f"esp32/{self._camera_id}/image"
        self._frame_rate = 30 
        self.video_folder = os.path.join(ASSETS_DIR, f"video1")

    def run(self):
        """
        Main function to run the ESP32 client.
        """
        self.client = Client(client_id=self._camera_id)
        if self._username and self._password:
            self.client.username_pw_set(self._username, self._password)
        
        if self._tls_cert:
            self.client.tls_set(ca_certs=self._tls_cert)

        try:
            self.client.connect(self._ip, self._port)
        except Exception as e:
            print(f"esp32/{self._camera_id}: Failed to connect to MQTT broker: {e}")
            return
        self.client.on_message = self.on_message
        self.client.on_connect = self.on_connect
        thread = Thread(target=self._send_images, daemon=True)
        thread.start()
        self.client.loop_forever()
        thread.join()
        
    def generate_esp32_id(self) -> str: 
        """
        Generate a random ESP32 ID.
        """  
        esp32_id = hex(random.randint(0, 16777216)) # Generate a random ESP32 ID
        esp32_id = esp32_id[2:].zfill(6) # Format the ID to be 4 digits long
        return esp32_id

    def on_connect(self, client, userdata, flags, rc):
        """
        Callback function to handle connection to the MQTT broker.
        """
        print(f"esp32/{self._camera_id}: Connected to MQTT broker with result code {rc}")
        self.client.subscribe(self._PING_TOPIC)
        

    def on_message(self, client, userdata, message: MQTTMessage):
        """
        Callback function to handle incoming messages.
        """
        if message.topic == self._PING_TOPIC:
            status = {
                "camera_id": f"{self._camera_id}",
                "frame_size": "800x600",
                "brightness": 0,
                "contrast": 0,
                "saturation": 0,
                "auto_exposure": 1,
                "exposure_value": 0,
                "auto_gain": 1,
                "gain_value": 0,
                "vertical_flip": 0,
                "horizontal_flip": 0,
                "led_on": 1
            }
            self.client.publish(self._PONG_TOPIC, json.dumps(status))

    
    def _send_images(self):
        """
        Function to send images from the video folder to the MQTT broker.
        """
        images = []
        image_files = [f for f in os.listdir(self.video_folder) if f.endswith('.jpg')]
        image_files.sort()
        for image_file in image_files:
            image_path = os.path.join(self.video_folder, image_file)
            with open(image_path, 'rb') as img_file:
                img_data = img_file.read()
                images.append(img_data)

        while True:
            for img_data in images:
                self.client.publish(self._IMAGE_TOPIC, img_data)
                time.sleep(1/self._frame_rate)




