"""GUI interface for SSH Copy ID tool using PySide2."""

from __future__ import annotations

import subprocess
import sys
import threading
from pathlib import Path

from PySide2.QtCore import Qt, Signal
from PySide2.QtGui import QFont
from PySide2.QtWidgets import (
    QApplication,
    QCheckBox,
    QFileDialog,
    QFormLayout,
    QFrame,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QMainWindow,
    QMessageBox,
    QPushButton,
    QSpinBox,
    QTextEdit,
    QVBoxLayout,
    QWidget,
)

from .cli import SSHCopyIDConfig, ssh_copy_id

CONNECT_TIMEOUT_CODE = 255
CONNECTION_TEST_TIMEOUT = 10  # seconds
CONNECTION_CONNECT_TIMEOUT = 5  # seconds


class SSHCopyIDGUI(QMainWindow):
    """Main window for SSH Copy ID GUI."""

    # Signals for logging messages and connection status
    log_message = Signal(str)
    connection_status = Signal(bool, str)  # (success, message)

    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle("SSH Copy ID - SSH Key Deployment Tool")
        self.setGeometry(100, 100, 600, 500)

        # Create central widget and layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # Create and add components
        self.create_header(main_layout)
        self.create_form(main_layout)
        self.create_buttons(main_layout)
        self.create_log_area(main_layout)

        # Connect signals
        self.log_message.connect(self.append_log)
        self.connection_status.connect(self.update_connection_status)

        # Initial log message
        self.log_message.emit("SSH Copy ID GUI initialized. Ready to deploy SSH keys.")

    def create_header(self, parent_layout: QVBoxLayout) -> None:
        """Create header section."""
        header_frame = QFrame()
        header_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        header_layout = QVBoxLayout(header_frame)

        title_label = QLabel("SSH Key Deployment Tool")
        title_font = QFont()
        title_font.setPointSize(16)
        title_font.setBold(True)
        title_label.setFont(title_font)
        title_label.setAlignment(Qt.AlignCenter)

        subtitle_label = QLabel("Deploy SSH public keys to remote servers securely")
        subtitle_label.setAlignment(Qt.AlignCenter)

        header_layout.addWidget(title_label)
        header_layout.addWidget(subtitle_label)
        parent_layout.addWidget(header_frame)

    def create_form(self, parent_layout: QVBoxLayout) -> None:
        """Create form for user input."""
        form_group = QFrame()
        form_group.setFrameStyle(QFrame.StyledPanel)
        form_layout = QFormLayout(form_group)

        # Hostname input with connection test
        hostname_layout = QHBoxLayout()
        self.hostname_input = QLineEdit()
        self.hostname_input.setPlaceholderText("e.g., 192.168.1.100 or example.com")
        self.hostname_input.textChanged.connect(self.on_hostname_changed)

        self.connection_status_label = QLabel("")
        self.connection_status_label.setMinimumWidth(30)
        self.connection_status_label.setAlignment(Qt.AlignCenter)
        self.connection_status_label.setStyleSheet(
            "font-size: 16px; font-weight: bold;",
        )

        self.test_connection_button = QPushButton("Test")
        self.test_connection_button.setMaximumWidth(60)
        self.test_connection_button.clicked.connect(self.test_connection)
        self.test_connection_button.setEnabled(False)

        hostname_layout.addWidget(self.hostname_input)
        hostname_layout.addWidget(self.connection_status_label)
        hostname_layout.addWidget(self.test_connection_button)
        form_layout.addRow("Hostname/IP:", hostname_layout)

        # Username input
        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText("Username for remote server")
        self.username_input.textChanged.connect(self.on_username_changed)
        form_layout.addRow("Username:", self.username_input)

        # Password input
        self.password_input = QLineEdit()
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setPlaceholderText("Password for remote server")
        self.password_input.textChanged.connect(self.on_password_changed)
        form_layout.addRow("Password:", self.password_input)

        # Port input
        self.port_input = QSpinBox()
        self.port_input.setRange(1, 65535)
        self.port_input.setValue(22)
        form_layout.addRow("SSH Port:", self.port_input)

        # Key file selection
        key_layout = QHBoxLayout()
        self.key_path_input = QLineEdit()
        self.key_path_input.setText("~/.ssh/id_rsa.pub")
        self.key_path_input.setPlaceholderText("Path to public key file")

        browse_button = QPushButton("Browse...")
        browse_button.clicked.connect(self.browse_key_file)

        key_layout.addWidget(self.key_path_input)
        key_layout.addWidget(browse_button)
        form_layout.addRow("Public Key:", key_layout)

        # Timeout setting
        self.timeout_input = QSpinBox()
        self.timeout_input.setRange(1, 300)
        self.timeout_input.setValue(30)
        self.timeout_input.setSuffix(" seconds")
        form_layout.addRow("Timeout:", self.timeout_input)

        # Verbose logging checkbox
        self.verbose_checkbox = QCheckBox("Enable verbose logging")
        form_layout.addRow("", self.verbose_checkbox)

        parent_layout.addWidget(form_group)

    def create_buttons(self, parent_layout: QVBoxLayout) -> None:
        """Create action buttons."""
        button_layout = QHBoxLayout()

        # Deploy button
        self.deploy_button = QPushButton("Deploy SSH Key")
        self.deploy_button.setStyleSheet("QPushButton { font-weight: bold; }")
        self.deploy_button.clicked.connect(self.deploy_key)
        button_layout.addWidget(self.deploy_button)

        # Clear button
        clear_button = QPushButton("Clear Form")
        clear_button.clicked.connect(self.clear_form)
        button_layout.addWidget(clear_button)

        # Quit button
        quit_button = QPushButton("Quit")
        quit_button.clicked.connect(self.close)
        button_layout.addWidget(quit_button)

        parent_layout.addLayout(button_layout)

    def create_log_area(self, parent_layout: QVBoxLayout) -> None:
        """Create log display area."""
        log_group = QFrame()
        log_group.setFrameStyle(QFrame.StyledPanel)
        log_layout = QVBoxLayout(log_group)

        log_label = QLabel("Deployment Log:")
        log_label.setStyleSheet("QLabel { font-weight: bold; }")
        log_layout.addWidget(log_label)

        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setMaximumHeight(150)
        log_layout.addWidget(self.log_text)

        parent_layout.addWidget(log_group)

    def on_hostname_changed(self, _: str) -> None:
        """Handle hostname input changes."""
        self.update_test_button_state()

    def on_username_changed(self, _: str) -> None:
        """Handle username input changes."""
        self.update_test_button_state()

    def on_password_changed(self, _: str) -> None:
        """Handle password input changes."""
        self.update_test_button_state()

    def update_test_button_state(self) -> None:
        """Update test button enabled state based on required fields."""
        hostname = self.hostname_input.text().strip()
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()

        # Enable test button only when all required fields are filled
        has_required_fields = bool(hostname and username and password)
        self.test_connection_button.setEnabled(has_required_fields)

        if not has_required_fields:
            self.connection_status_label.setText("")
            self.connection_status_label.setStyleSheet(
                "font-size: 16px; font-weight: bold;",
            )

    def test_connection(self) -> None:
        """Test SSH connection to the specified host."""
        hostname = self.hostname_input.text().strip()
        port = self.port_input.value()
        username = self.username_input.text().strip() or "test"

        if not hostname:
            return

        # Update UI to show testing state
        self.connection_status_label.setText("⏳")
        self.connection_status_label.setStyleSheet(
            "color: orange; font-size: 16px; font-weight: bold;",
        )
        self.test_connection_button.setEnabled(False)
        self.log_message.emit(f"Testing connection to {hostname}:{port}...")

        # Run connection test in separate thread to avoid blocking UI
        test_thread = threading.Thread(
            target=self._perform_connection_test,
            args=(hostname, port, username),
            daemon=True,
        )
        test_thread.start()

    def _perform_connection_test(self, hostname: str, port: int, username: str) -> None:
        """Perform actual SSH connection test in background thread."""
        try:
            # Use ssh with minimal command to test connectivity
            # This tests if the SSH port is open and responsive
            cmd = [
                "ssh",
                "-p",
                str(port),
                "-o",
                f"ConnectTimeout={CONNECTION_CONNECT_TIMEOUT}",
                "-o",
                "StrictHostKeyChecking=no",
                "-o",
                "UserKnownHostsFile=/dev/null",
                "-o",
                "BatchMode=yes",
                f"{username}@{hostname}",
                "echo",
                "connection_test",
            ]

            process = subprocess.run(cmd, capture_output=True, text=True, timeout=CONNECTION_TEST_TIMEOUT, check=False)

            # If we get a response or authentication failure (but not connection refused),
            # the connection is successful
            if process.returncode == 0 or "Permission denied" in process.stderr:
                self.connection_status.emit(True, "Connected successfully")
            elif "Connection refused" in process.stderr:
                self.connection_status.emit(False, "Connection refused")
            elif "Network is unreachable" in process.stderr:
                self.connection_status.emit(False, "Network unreachable")
            elif "Operation timed out" in process.stderr or process.returncode == CONNECT_TIMEOUT_CODE:
                self.connection_status.emit(False, "Connection timeout")
            else:
                # Other SSH errors usually mean the connection was established
                # but authentication failed, which is still a successful connection test
                self.connection_status.emit(True, "Connected (auth required)")

        except subprocess.TimeoutExpired:
            self.connection_status.emit(False, "Test timeout")
        except FileNotFoundError:
            self.connection_status.emit(False, "SSH command not found")
        except PermissionError:
            self.connection_status.emit(False, "Permission denied")
        except OSError as e:
            self.connection_status.emit(False, f"System error: {e!s}")

        # Re-enable the test button
        self.test_connection_button.setEnabled(True)

    def update_connection_status(self, success: bool, message: str) -> None:  # noqa: FBT001
        """Update the connection status display."""
        if success:
            self.connection_status_label.setText("✓")
            self.connection_status_label.setStyleSheet(
                "color: green; font-size: 16px; font-weight: bold;",
            )
            self.log_message.emit(f"✅ {message}")
        else:
            self.connection_status_label.setText("✗")
            self.connection_status_label.setStyleSheet(
                "color: red; font-size: 16px; font-weight: bold;",
            )
            self.log_message.emit(f"❌ {message}")

    def browse_key_file(self) -> None:
        """Open file dialog to select public key file."""
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "Select Public Key File",
            str(Path.home() / ".ssh"),
            "Public Key Files (*.pub);;All Files (*)",
        )

        if file_path:
            self.key_path_input.setText(file_path)

    def deploy_key(self) -> None:
        """Deploy SSH key to remote server."""
        try:
            # Validate inputs
            hostname = self.hostname_input.text().strip()
            username = self.username_input.text().strip()
            password = self.password_input.text()
            key_path = self.key_path_input.text().strip()

            if not all([hostname, username, password]):
                QMessageBox.warning(
                    self,
                    "Input Error",
                    "Please fill in all required fields (Hostname, Username, Password).",
                )
                return

            # Warn if connection test hasn't been performed
            if self.connection_status_label.text() not in {"✓", "✗"}:
                reply = QMessageBox.question(
                    self,
                    "Connection Test",
                    ("Connection test has not been performed. Do you want to continue anyway?"),
                    QMessageBox.Yes | QMessageBox.No,
                    QMessageBox.No,
                )
                if reply == QMessageBox.No:
                    return

            # Create configuration
            config = SSHCopyIDConfig(
                hostname=hostname,
                username=username,
                password=password,
                port=self.port_input.value(),
                public_key_path=key_path,
                timeout=self.timeout_input.value(),
            )

            # Disable deploy button during operation
            self.deploy_button.setEnabled(False)
            self.deploy_button.setText("Deploying...")
            self.log_message.emit(
                f"Starting deployment to {username}@{hostname}:{config.port}",
            )
            self.log_message.emit(f"Using public key: {config.expanded_key_path}")

            # Perform deployment
            ssh_copy_id(config)

            # Success message
            self.log_message.emit("✅ SSH key deployment completed successfully!")
            QMessageBox.information(
                self,
                "Success",
                "SSH key has been successfully deployed to the remote server!",
            )

        except FileNotFoundError as e:
            error_msg = f"❌ Deployment failed: {e!s}"
            self.log_message.emit(error_msg)
            QMessageBox.critical(
                self,
                "Deployment Error",
                f"Failed to deploy SSH key:\n\n{e!s}",
            )
        except PermissionError as e:
            error_msg = f"❌ Deployment failed: {e!s}"
            self.log_message.emit(error_msg)
            QMessageBox.critical(
                self,
                "Deployment Error",
                f"Failed to deploy SSH key:\n\n{e!s}",
            )
        except OSError as e:
            error_msg = f"❌ Deployment failed: {e!s}"
            self.log_message.emit(error_msg)
            QMessageBox.critical(
                self,
                "Deployment Error",
                f"Failed to deploy SSH key:\n\n{e!s}",
            )
        finally:
            # Re-enable deploy button
            self.deploy_button.setEnabled(True)
            self.deploy_button.setText("Deploy SSH Key")

    def clear_form(self) -> None:
        """Clear all form fields."""
        self.hostname_input.clear()
        self.username_input.clear()
        self.password_input.clear()
        self.key_path_input.setText("~/.ssh/id_rsa.pub")
        self.port_input.setValue(22)
        self.timeout_input.setValue(30)
        self.verbose_checkbox.setChecked(False)
        self.log_text.clear()
        self.log_message.emit("Form cleared. Ready for new deployment.")
        # Update test button state after clearing
        self.update_test_button_state()

    def append_log(self, message: str) -> None:
        """Append message to log area."""
        self.log_text.append(message)


def main() -> None:
    """Run entry point for the graphical user interface."""
    app = QApplication(sys.argv)

    # Set application properties
    app.setApplicationName("SSH Copy ID")
    app.setApplicationVersion("1.0.0")

    # Create and show main window
    window = SSHCopyIDGUI()
    window.show()

    # Run application
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
