import os
import sys

from PyQt6.QtWidgets import QCheckBox, QGroupBox, QFormLayout, QLineEdit, QPushButton, QFileDialog, QHBoxLayout
from PyQt6.QtGui import QRegularExpressionValidator, QIcon
from PyQt6.QtCore import QRegularExpression

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

class MQTTGroup(QGroupBox):
    """
    MQTTGroup is a class that represents a group of widgets for configuring the MQTT settings.
    """

    def __init__(self, title: str):
        super().__init__(title)
    
        # << -- MQTT Broker Setup -- >>
        self._broker_ip_edit = QLineEdit()
        self._broker_port_edit = QLineEdit()
        self._broker_ip_edit.setPlaceholderText("127.0.0.1")
        self._broker_port_edit.setPlaceholderText("1883")
        self._broker_ip_edit.setValidator(QRegularExpressionValidator(QRegularExpression(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")))
        self._broker_port_edit.setValidator(QRegularExpressionValidator(QRegularExpression(r"^\d{1,5}$")))

        # << -- MQTT Credentials Setup -- >>
        self._use_credentials_checkbox = QCheckBox()
        self._username_edit = QLineEdit()
        self._password_edit = QLineEdit()
        self._password_button = QPushButton()
        self._password_layout = QHBoxLayout()
        self._password_edit.setEchoMode(QLineEdit.EchoMode.Password)
        self._password_button.setCheckable(True)
        self._password_button.setMaximumSize(30, 30)
        self._password_button.setIcon(QIcon(f"{ASSETS_DIR}/show.png"))
        self._use_credentials_checkbox.setChecked(False)
        self._password_button.setChecked(False)
        self._password_layout.addWidget(self._password_edit)
        self._password_layout.addWidget(self._password_button)

        # << -- MQTT TLS Setup -- >>
        self._tls_checkbox = QCheckBox()
        self._tls_button = QPushButton("Select Certificate")
        self._tls_checkbox.setChecked(False)
        self._tls_path = None

        # << -- MQTT Form Setup -- >>
        self._layout = QFormLayout()
        self._layout.addRow("Broker IP", self._broker_ip_edit)
        self._layout.addRow("Broker Port", self._broker_port_edit)
        self._layout.addRow("Require Credentials", self._use_credentials_checkbox)
        self._layout.addRow("    Username", self._username_edit)
        self._layout.addRow("    Password", self._password_layout)
        self._layout.addRow("Use TLS", self._tls_checkbox)
        self._layout.addRow("    Certificate", self._tls_button)
        self._layout.setRowVisible(self._password_layout, False)
        self._layout.setRowVisible(self._username_edit, False)
        self._layout.setRowVisible(self._tls_button, False)

        # << -- Callback Setup -- >>
        self._use_credentials_checkbox.checkStateChanged.connect(self._toggle_credentials_options)
        self._tls_checkbox.checkStateChanged.connect(self._toggle_tls_options)
        self._tls_button.clicked.connect(self._select_tls_certificate)
        self._password_button.clicked.connect(self._toggle_password_echo_mode)

        # << -- Layout Setup -- >>
        self.setLayout(self._layout)

    def _toggle_password_echo_mode(self):
        """Switches the echo mode of the password edit field between normal and password."""
        if self._password_button.isChecked():
            self._password_edit.setEchoMode(QLineEdit.EchoMode.Normal)
            self._password_button.setIcon(QIcon(f"{ASSETS_DIR}/hide.png"))
        else:
            self._password_edit.setEchoMode(QLineEdit.EchoMode.Password)
            self._password_button.setIcon(QIcon(f"{ASSETS_DIR}/show.png"))

    def _toggle_credentials_options(self):
        """
        Show or hide the username and password fields based on the state of the credentials checkbox.
        """
        if self._use_credentials_checkbox.isChecked():
            self._layout.setRowVisible(self._username_edit, True)
            self._layout.setRowVisible(self._password_layout, True)
        else:
            self._layout.setRowVisible(self._username_edit, False)
            self._layout.setRowVisible(self._password_layout, False)
        

    def _toggle_tls_options(self):
        """
        Show or hide the TLS certificate field based on the state of the TLS checkbox.
        """
        if self._tls_checkbox.isChecked():
            self._layout.setRowVisible(self._tls_button, True)
        else:
            self._layout.setRowVisible(self._tls_button, False)


    def _select_tls_certificate(self):
        """
        Open a file dialog to select the TLS certificate file.
        """
        self._tls_path = QFileDialog.getOpenFileName(self, "Select Certificate", "", "Certificate Files (*.crt *.pem)")[0]
        if self._tls_path:
            file_name = self._tls_path.split("/")[-1]
            self._tls_button.setText("(" + file_name + ")")

    
    @property
    def broker_ip(self) -> str:
        """Return the broker IP address."""
        return self._broker_ip_edit.text().strip()
    
    @broker_ip.setter
    def broker_ip(self, value: str) -> None:
        """Set the broker IP address."""
        self._broker_ip_edit.setText(value)
    
    @property
    def broker_port(self) -> int:
        """Return the broker port."""
        try:
            return int(self._broker_port_edit.text())
        except ValueError:
            return 0
        
    @broker_port.setter
    def broker_port(self, value: int) -> None:
        """Set the broker port."""
        self._broker_port_edit.setText(str(value))

    @property
    def username(self) -> str:
        """Return the username."""
        if not self._use_credentials_checkbox.isChecked():
            return None
        return self._username_edit.text().strip()    
    
    @username.setter
    def username(self, value: str) -> None:
        """Set the username."""
        self._username_edit.setText(value)

    
    @property
    def password(self) -> str:
        """Return the password."""
        if not self._use_credentials_checkbox.isChecked():
            return None
        return self._password_edit.text().strip()
    
    @property
    def tls_path(self) -> str:
        """Return the TLS certificate path."""
        if not self._tls_checkbox.isChecked():
            return None
        return self._tls_path
    
    @tls_path.setter
    def tls_path(self, value: str) -> None:
        """Set the TLS certificate path."""
        self._tls_path = value
        file_name = self._tls_path.split("/")[-1]
        self._tls_button.setText("(" + file_name + ")")
    
    @property
    def use_credentials(self) -> bool:
        """Return whether to use credentials."""
        return self._use_credentials_checkbox.isChecked()
    
    @use_credentials.setter
    def use_credentials(self, value: bool) -> None:
        """Set whether to use credentials."""
        self._use_credentials_checkbox.setChecked(value)
        self._toggle_credentials_options()
    
    @property
    def use_tls(self) -> bool:
        """Return whether to use TLS."""
        return self._tls_checkbox.isChecked()
    
    @use_tls.setter
    def use_tls(self, value: bool) -> None:
        """Set whether to use TLS."""
        self._tls_checkbox.setChecked(value)
        self._toggle_tls_options()
