"""Settings dialog for configuration management."""

import logging
from pathlib import Path
from typing import List, Optional

from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QDialog,
    QDialogButtonBox,
    QFileDialog,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QListWidget,
    QListWidgetItem,
    QPushButton,
    QSpinBox,
    QTabWidget,
    QTableWidget,
    QTableWidgetItem,
    QVBoxLayout,
    QWidget,
)

from webdrop_bridge.config import Config, ConfigurationError
from webdrop_bridge.core.config_manager import ConfigExporter, ConfigProfile, ConfigValidator
from webdrop_bridge.utils.logging import reconfigure_logging

logger = logging.getLogger(__name__)


class SettingsDialog(QDialog):
    """Dialog for managing application settings and configuration.
    
    Provides tabs for:
    - Paths: Manage allowed root directories
    - URLs: Manage allowed web URLs
    - Logging: Configure logging settings
    - Window: Manage window size and behavior
    - Profiles: Save/load/delete configuration profiles
    """

    def __init__(self, config: Config, parent=None):
        """Initialize the settings dialog.
        
        Args:
            config: Current application configuration
            parent: Parent widget
        """
        super().__init__(parent)
        self.config = config
        self.profile_manager = ConfigProfile()
        self.setWindowTitle("Settings")
        self.setGeometry(100, 100, 600, 500)
        
        self.setup_ui()

    def setup_ui(self) -> None:
        """Set up the dialog UI with tabs."""
        layout = QVBoxLayout()
        
        # Create tab widget
        self.tabs = QTabWidget()
        
        # Add tabs
        self.tabs.addTab(self._create_web_source_tab(), "Web Source")
        self.tabs.addTab(self._create_paths_tab(), "Paths")
        self.tabs.addTab(self._create_urls_tab(), "URLs")
        self.tabs.addTab(self._create_logging_tab(), "Logging")
        self.tabs.addTab(self._create_window_tab(), "Window")
        self.tabs.addTab(self._create_profiles_tab(), "Profiles")
        
        layout.addWidget(self.tabs)
        
        # Add buttons
        button_box = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
        )
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)
        
        self.setLayout(layout)

    def accept(self) -> None:
        """Handle OK button - save configuration changes to file.
        
        Validates configuration and saves to the default config path.
        Applies log level changes immediately in the running application.
        If validation or save fails, shows error and stays in dialog.
        """
        try:
            # Get updated configuration data from UI
            config_data = self.get_config_data()
            
            # Convert URL mappings from dict to URLMapping objects
            from webdrop_bridge.config import URLMapping
            
            url_mappings = [
                URLMapping(
                    url_prefix=m["url_prefix"],
                    local_path=m["local_path"]
                )
                for m in config_data["url_mappings"]
            ]
            
            # Update the config object with new values
            old_log_level = self.config.log_level
            self.config.log_level = config_data["log_level"]
            self.config.log_file = Path(config_data["log_file"]) if config_data["log_file"] else None
            self.config.allowed_roots = [Path(r).resolve() for r in config_data["allowed_roots"]]
            self.config.allowed_urls = config_data["allowed_urls"]
            self.config.webapp_url = config_data["webapp_url"]
            self.config.url_mappings = url_mappings
            self.config.window_width = config_data["window_width"]
            self.config.window_height = config_data["window_height"]
            
            # Save to file (creates parent dirs if needed)
            config_path = Config.get_default_config_path()
            self.config.to_file(config_path)
            
            logger.info(f"Configuration saved to {config_path}")
            logger.info(f"  Log level: {self.config.log_level} (was: {old_log_level})")
            logger.info(f"  Window size: {self.config.window_width}x{self.config.window_height}")
            
            # Apply log level change immediately to running application
            if old_log_level != self.config.log_level:
                logger.info(f"🔄 Updating log level: {old_log_level} → {self.config.log_level}")
                reconfigure_logging(
                    logger_name="webdrop_bridge",
                    level=self.config.log_level,
                    log_file=self.config.log_file
                )
                logger.info(f"✅ Log level updated to {self.config.log_level}")
            
            # Call parent accept to close dialog
            super().accept()
            
        except ConfigurationError as e:
            logger.error(f"Configuration error: {e}")
            self._show_error(f"Configuration Error:\n\n{e}")
        except Exception as e:
            logger.error(f"Failed to save configuration: {e}", exc_info=True)
            self._show_error(f"Failed to save configuration:\n\n{e}")

    def _create_web_source_tab(self) -> QWidget:
        """Create web source configuration tab."""
        from PySide6.QtWidgets import QTableWidget, QTableWidgetItem
        
        widget = QWidget()
        layout = QVBoxLayout()
        
        # Webapp URL configuration
        layout.addWidget(QLabel("Web Application URL:"))
        url_layout = QHBoxLayout()
        
        self.webapp_url_input = QLineEdit()
        self.webapp_url_input.setText(self.config.webapp_url)
        self.webapp_url_input.setPlaceholderText("e.g., http://localhost:8080 or file:///./webapp/index.html")
        url_layout.addWidget(self.webapp_url_input)
        
        open_btn = QPushButton("Open")
        open_btn.clicked.connect(self._open_webapp_url)
        url_layout.addWidget(open_btn)
        
        layout.addLayout(url_layout)
        
        # URL Mappings (Azure Blob URL → Local Path)
        layout.addWidget(QLabel("URL Mappings (Azure Blob Storage → Local Paths):"))
        
        # Create table for URL mappings
        self.url_mappings_table = QTableWidget()
        self.url_mappings_table.setColumnCount(2)
        self.url_mappings_table.setHorizontalHeaderLabels(["URL Prefix", "Local Path"])
        self.url_mappings_table.horizontalHeader().setStretchLastSection(True)
        
        # Populate from config
        for mapping in self.config.url_mappings:
            row = self.url_mappings_table.rowCount()
            self.url_mappings_table.insertRow(row)
            self.url_mappings_table.setItem(row, 0, QTableWidgetItem(mapping.url_prefix))
            self.url_mappings_table.setItem(row, 1, QTableWidgetItem(mapping.local_path))
        
        layout.addWidget(self.url_mappings_table)
        
        # Buttons for URL mapping management
        button_layout = QHBoxLayout()
        
        add_mapping_btn = QPushButton("Add Mapping")
        add_mapping_btn.clicked.connect(self._add_url_mapping)
        button_layout.addWidget(add_mapping_btn)
        
        edit_mapping_btn = QPushButton("Edit Selected")
        edit_mapping_btn.clicked.connect(self._edit_url_mapping)
        button_layout.addWidget(edit_mapping_btn)
        
        remove_mapping_btn = QPushButton("Remove Selected")
        remove_mapping_btn.clicked.connect(self._remove_url_mapping)
        button_layout.addWidget(remove_mapping_btn)
        
        layout.addLayout(button_layout)
        layout.addStretch()
        
        widget.setLayout(layout)
        return widget
    
    def _open_webapp_url(self) -> None:
        """Open the webapp URL in the default browser."""
        import webbrowser
        url = self.webapp_url_input.text().strip()
        if url:
            # Handle file:// URLs
            try:
                webbrowser.open(url)
            except Exception as e:
                logger.error(f"Failed to open URL: {e}")
                self._show_error(f"Failed to open URL:\n\n{e}")
    
    def _add_url_mapping(self) -> None:
        """Add new URL mapping."""
        from PySide6.QtWidgets import QInputDialog
        
        url_prefix, ok1 = QInputDialog.getText(
            self,
            "Add URL Mapping",
            "Enter Azure Blob Storage URL prefix:\n(e.g., https://myblob.blob.core.windows.net/container/)"
        )
        
        if ok1 and url_prefix:
            local_path, ok2 = QInputDialog.getText(
                self,
                "Add URL Mapping",
                "Enter local file system path:\n(e.g., C:\\Share or /mnt/share)"
            )
            
            if ok2 and local_path:
                row = self.url_mappings_table.rowCount()
                self.url_mappings_table.insertRow(row)
                self.url_mappings_table.setItem(row, 0, QTableWidgetItem(url_prefix))
                self.url_mappings_table.setItem(row, 1, QTableWidgetItem(local_path))
    
    def _edit_url_mapping(self) -> None:
        """Edit selected URL mapping."""
        from PySide6.QtWidgets import QInputDialog
        
        current_row = self.url_mappings_table.currentRow()
        if current_row < 0:
            self._show_error("Please select a mapping to edit")
            return
        
        url_prefix = self.url_mappings_table.item(current_row, 0).text()
        local_path = self.url_mappings_table.item(current_row, 1).text()
        
        new_url_prefix, ok1 = QInputDialog.getText(
            self,
            "Edit URL Mapping",
            "Enter Azure Blob Storage URL prefix:",
            text=url_prefix
        )
        
        if ok1 and new_url_prefix:
            new_local_path, ok2 = QInputDialog.getText(
                self,
                "Edit URL Mapping",
                "Enter local file system path:",
                text=local_path
            )
            
            if ok2 and new_local_path:
                self.url_mappings_table.setItem(current_row, 0, QTableWidgetItem(new_url_prefix))
                self.url_mappings_table.setItem(current_row, 1, QTableWidgetItem(new_local_path))
    
    def _remove_url_mapping(self) -> None:
        """Remove selected URL mapping."""
        current_row = self.url_mappings_table.currentRow()
        if current_row >= 0:
            self.url_mappings_table.removeRow(current_row)

    def _create_paths_tab(self) -> QWidget:
        """Create paths configuration tab."""
        widget = QWidget()
        layout = QVBoxLayout()
        
        layout.addWidget(QLabel("Allowed root directories for file access:"))
        
        # List widget for paths
        self.paths_list = QListWidget()
        for path in self.config.allowed_roots:
            self.paths_list.addItem(str(path))
        layout.addWidget(self.paths_list)
        
        # Buttons for path management
        button_layout = QHBoxLayout()
        
        add_path_btn = QPushButton("Add Path")
        add_path_btn.clicked.connect(self._add_path)
        button_layout.addWidget(add_path_btn)
        
        remove_path_btn = QPushButton("Remove Selected")
        remove_path_btn.clicked.connect(self._remove_path)
        button_layout.addWidget(remove_path_btn)
        
        layout.addLayout(button_layout)
        layout.addStretch()
        
        widget.setLayout(layout)
        return widget

    def _create_urls_tab(self) -> QWidget:
        """Create URLs configuration tab."""
        widget = QWidget()
        layout = QVBoxLayout()
        
        layout.addWidget(QLabel("Allowed web URLs (supports wildcards like http://*.example.com):"))
        
        # List widget for URLs
        self.urls_list = QListWidget()
        for url in self.config.allowed_urls:
            self.urls_list.addItem(url)
        layout.addWidget(self.urls_list)
        
        # Buttons for URL management
        button_layout = QHBoxLayout()
        
        add_url_btn = QPushButton("Add URL")
        add_url_btn.clicked.connect(self._add_url)
        button_layout.addWidget(add_url_btn)
        
        remove_url_btn = QPushButton("Remove Selected")
        remove_url_btn.clicked.connect(self._remove_url)
        button_layout.addWidget(remove_url_btn)
        
        layout.addLayout(button_layout)
        layout.addStretch()
        
        widget.setLayout(layout)
        return widget

    def _create_logging_tab(self) -> QWidget:
        """Create logging configuration tab."""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # Log level selection
        layout.addWidget(QLabel("Log Level:"))
        from PySide6.QtWidgets import QComboBox
        self.log_level_combo: QComboBox = self._create_log_level_widget()
        layout.addWidget(self.log_level_combo)
        
        # Log file path
        layout.addWidget(QLabel("Log File (optional):"))
        log_file_layout = QHBoxLayout()
        
        self.log_file_input = QLineEdit()
        self.log_file_input.setText(str(self.config.log_file) if self.config.log_file else "")
        log_file_layout.addWidget(self.log_file_input)
        
        browse_btn = QPushButton("Browse...")
        browse_btn.clicked.connect(self._browse_log_file)
        log_file_layout.addWidget(browse_btn)
        
        layout.addLayout(log_file_layout)
        
        layout.addStretch()
        widget.setLayout(layout)
        return widget

    def _create_window_tab(self) -> QWidget:
        """Create window settings tab."""
        widget = QWidget()
        layout = QVBoxLayout()
        
        # Window width
        width_layout = QHBoxLayout()
        width_layout.addWidget(QLabel("Window Width:"))
        self.width_spin = QSpinBox()
        self.width_spin.setMinimum(400)
        self.width_spin.setMaximum(5000)
        self.width_spin.setValue(self.config.window_width)
        width_layout.addWidget(self.width_spin)
        width_layout.addStretch()
        layout.addLayout(width_layout)
        
        # Window height
        height_layout = QHBoxLayout()
        height_layout.addWidget(QLabel("Window Height:"))
        self.height_spin = QSpinBox()
        self.height_spin.setMinimum(300)
        self.height_spin.setMaximum(5000)
        self.height_spin.setValue(self.config.window_height)
        height_layout.addWidget(self.height_spin)
        height_layout.addStretch()
        layout.addLayout(height_layout)
        
        layout.addStretch()
        widget.setLayout(layout)
        return widget

    def _create_profiles_tab(self) -> QWidget:
        """Create profiles management tab."""
        widget = QWidget()
        layout = QVBoxLayout()
        
        layout.addWidget(QLabel("Saved Configuration Profiles:"))
        
        # List of profiles
        self.profiles_list = QListWidget()
        self._refresh_profiles_list()
        layout.addWidget(self.profiles_list)
        
        # Profile management buttons
        button_layout = QHBoxLayout()
        
        save_profile_btn = QPushButton("Save as Profile")
        save_profile_btn.clicked.connect(self._save_profile)
        button_layout.addWidget(save_profile_btn)
        
        load_profile_btn = QPushButton("Load Profile")
        load_profile_btn.clicked.connect(self._load_profile)
        button_layout.addWidget(load_profile_btn)
        
        delete_profile_btn = QPushButton("Delete Profile")
        delete_profile_btn.clicked.connect(self._delete_profile)
        button_layout.addWidget(delete_profile_btn)
        
        layout.addLayout(button_layout)
        
        # Export/Import buttons
        export_layout = QHBoxLayout()
        
        export_btn = QPushButton("Export Configuration")
        export_btn.clicked.connect(self._export_config)
        export_layout.addWidget(export_btn)
        
        import_btn = QPushButton("Import Configuration")
        import_btn.clicked.connect(self._import_config)
        export_layout.addWidget(import_btn)
        
        layout.addLayout(export_layout)
        layout.addStretch()
        
        widget.setLayout(layout)
        return widget

    def _create_log_level_widget(self):
        """Create log level selection widget."""
        from PySide6.QtWidgets import QComboBox
        
        combo = QComboBox()
        levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
        combo.addItems(levels)
        combo.setCurrentText(self.config.log_level)
        return combo

    def _add_path(self) -> None:
        """Add a new allowed path."""
        path = QFileDialog.getExistingDirectory(self, "Select Directory to Allow")
        if path:
            self.paths_list.addItem(path)

    def _remove_path(self) -> None:
        """Remove selected path."""
        if self.paths_list.currentItem():
            self.paths_list.takeItem(self.paths_list.row(self.paths_list.currentItem()))

    def _add_url(self) -> None:
        """Add a new allowed URL."""
        from PySide6.QtWidgets import QInputDialog
        
        url, ok = QInputDialog.getText(
            self,
            "Add URL",
            "Enter URL pattern (e.g., http://example.com or http://*.example.com):"
        )
        if ok and url:
            self.urls_list.addItem(url)

    def _remove_url(self) -> None:
        """Remove selected URL."""
        if self.urls_list.currentItem():
            self.urls_list.takeItem(self.urls_list.row(self.urls_list.currentItem()))

    def _browse_log_file(self) -> None:
        """Browse for log file location."""
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "Select Log File",
            str(Path.home()),
            "Log Files (*.log);;All Files (*)"
        )
        if file_path:
            self.log_file_input.setText(file_path)

    def _refresh_profiles_list(self) -> None:
        """Refresh the list of available profiles."""
        self.profiles_list.clear()
        for profile_name in self.profile_manager.list_profiles():
            self.profiles_list.addItem(profile_name)

    def _save_profile(self) -> None:
        """Save current configuration as a profile."""
        from PySide6.QtWidgets import QInputDialog
        
        profile_name, ok = QInputDialog.getText(
            self,
            "Save Profile",
            "Enter profile name (e.g., work, personal):"
        )
        
        if ok and profile_name:
            try:
                self.profile_manager.save_profile(profile_name, self.config)
                self._refresh_profiles_list()
            except ConfigurationError as e:
                self._show_error(f"Failed to save profile: {e}")

    def _load_profile(self) -> None:
        """Load a saved profile."""
        current_item = self.profiles_list.currentItem()
        if not current_item:
            self._show_error("Please select a profile to load")
            return
        
        profile_name = current_item.text()
        try:
            config_data = self.profile_manager.load_profile(profile_name)
            self._apply_config_data(config_data)
        except ConfigurationError as e:
            self._show_error(f"Failed to load profile: {e}")

    def _delete_profile(self) -> None:
        """Delete a saved profile."""
        current_item = self.profiles_list.currentItem()
        if not current_item:
            self._show_error("Please select a profile to delete")
            return
        
        profile_name = current_item.text()
        try:
            self.profile_manager.delete_profile(profile_name)
            self._refresh_profiles_list()
        except ConfigurationError as e:
            self._show_error(f"Failed to delete profile: {e}")

    def _export_config(self) -> None:
        """Export configuration to file."""
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "Export Configuration",
            str(Path.home()),
            "JSON Files (*.json);;All Files (*)"
        )
        
        if file_path:
            try:
                ConfigExporter.export_to_json(self.config, Path(file_path))
            except ConfigurationError as e:
                self._show_error(f"Failed to export configuration: {e}")

    def _import_config(self) -> None:
        """Import configuration from file."""
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "Import Configuration",
            str(Path.home()),
            "JSON Files (*.json);;All Files (*)"
        )
        
        if file_path:
            try:
                config_data = ConfigExporter.import_from_json(Path(file_path))
                self._apply_config_data(config_data)
            except ConfigurationError as e:
                self._show_error(f"Failed to import configuration: {e}")

    def _apply_config_data(self, config_data: dict) -> None:
        """Apply imported configuration data to UI.
        
        Args:
            config_data: Configuration dictionary
        """
        # Apply paths
        self.paths_list.clear()
        for path in config_data.get("allowed_roots", []):
            self.paths_list.addItem(str(path))
        
        # Apply URLs
        self.urls_list.clear()
        for url in config_data.get("allowed_urls", []):
            self.urls_list.addItem(url)
        
        # Apply logging settings
        self.log_level_combo.setCurrentText(config_data.get("log_level", "INFO"))
        log_file = config_data.get("log_file")
        self.log_file_input.setText(str(log_file) if log_file else "")
        
        # Apply window settings
        self.width_spin.setValue(config_data.get("window_width", 800))
        self.height_spin.setValue(config_data.get("window_height", 600))

    def get_config_data(self) -> dict:
        """Get updated configuration data from dialog.
        
        Returns:
            Configuration dictionary
            
        Raises:
            ConfigurationError: If configuration is invalid
        """
        config_data = {
            "app_name": self.config.app_name,
            "app_version": self.config.app_version,
            "log_level": self.log_level_combo.currentText(),
            "log_file": self.log_file_input.text() or None,
            "allowed_roots": [self.paths_list.item(i).text() for i in range(self.paths_list.count())],
            "allowed_urls": [self.urls_list.item(i).text() for i in range(self.urls_list.count())],
            "webapp_url": self.webapp_url_input.text().strip(),
            "url_mappings": [
                {
                    "url_prefix": self.url_mappings_table.item(i, 0).text(),
                    "local_path": self.url_mappings_table.item(i, 1).text()
                }
                for i in range(self.url_mappings_table.rowCount())
            ],
            "window_width": self.width_spin.value(),
            "window_height": self.height_spin.value(),
            "enable_logging": self.config.enable_logging,
        }
        
        # Validate
        ConfigValidator.validate_or_raise(config_data)
        
        return config_data

    def _show_error(self, message: str) -> None:
        """Show error message to user.
        
        Args:
            message: Error message
        """
        from PySide6.QtWidgets import QMessageBox
        QMessageBox.critical(self, "Error", message)
