from argparse import ArgumentParser
from ESP32Client import ESP32Client

import threading
import os
import signal

signal.signal(signal.SIGINT, signal.SIG_DFL) # Allow Ctrl+C to terminate the script


def validate_arguments(parser: ArgumentParser, ip: str, port: int, number_to_emulate: int, username: str, password: str, crt: str):
    """
    Validate the command line arguments.
    """
    if number_to_emulate <= 0 or number_to_emulate > 13:
        parser.error("Number of ESP32 devices to emulate must be between 1 and 12.")
    
    if port < 0 or port > 65535:
        parser.error("Port number must be between 0 and 65535.")
    
    if not username and password or username and not password: # If one is provided, the other must be provided as well
        parser.error("Username and password are required if one is provided.")

    if crt:
        if not os.path.isfile(crt) or not os.access(crt, os.R_OK): # Check if the certificate file exists and is readable
            parser.error(f"Certificate file {crt} does not exist or is not readable.")
        if not crt.endswith(".crt"): # Check if the certificate file has the correct extension
            parser.error(f"Certificate file {crt} must be a .crt file.")


def get_arguments():
    """
    Parse command line arguments.
    """
    parser = ArgumentParser(description="ESP32-CAM Simulator")
    parser.add_argument("-i", "--ip", type=str, required=True, help="MQTT broker ip address (Required)")
    parser.add_argument("-p", "--port", type=int, required=True, help="MQTT broker port (Required)")
    parser.add_argument("-n", "--number", type=int, required=True, help="Number of ESP32 devices to emulate (Required)")
    parser.add_argument("-U", "--username", type=str, required=False, help="Username for the MQTT broker (Optional)")
    parser.add_argument("-P", "--password", type=str, required=False, help="Password for the MQTT broker (Optional)")
    parser.add_argument("-c", "--crt", type=str, required=False, help="Path to the TLS certificate file (Optional)")
    arguments = parser.parse_args()

    ip, port = arguments.ip, arguments.port
    number_to_emulate = arguments.number
    username, password = arguments.username, arguments.password
    crt = arguments.crt
    validate_arguments(parser, ip, port, number_to_emulate, username, password, crt)
    return ip, port, number_to_emulate, username, password, crt


def main():
    """
    Main function to run the ESP32 simulator.
    """
    ip, port, number_to_emulate, username, password, crt = get_arguments()
    threads = []
    for _ in range(number_to_emulate):
        client = ESP32Client(ip, port, username, password, crt)
        thread = threading.Thread(target=client.run)
        threads.append(thread)
        thread.start()
    
    for thread in threads: # Wait for all threads to finish
        thread.join()


if __name__ == "__main__":
    main()
    

    