"""Unit tests for MainWindow component."""

from unittest.mock import patch

import pytest
from PySide6.QtWidgets import QToolBar

from webdrop_bridge.config import Config
from webdrop_bridge.ui.main_window import MainWindow


@pytest.fixture
def sample_config(tmp_path):
    """Provide a test configuration."""
    # Create required directories
    allowed_root = tmp_path / "allowed"
    allowed_root.mkdir(exist_ok=True)

    # Create webapp HTML
    webapp_dir = tmp_path / "webapp"
    webapp_dir.mkdir(exist_ok=True)
    webapp_file = webapp_dir / "index.html"
    webapp_file.write_text("<html><body>Test</body></html>")

    config = Config(
        app_name="Test WebDrop",
        app_version="1.0.0",
        log_level="INFO",
        log_file=None,
        allowed_roots=[allowed_root],
        allowed_urls=["localhost", "127.0.0.1"],
        webapp_url=str(webapp_file),
        window_width=800,
        window_height=600,
        window_title="Test WebDrop v1.0.0",
        enable_logging=False,
    )
    return config


class TestMainWindowInitialization:
    """Test MainWindow initialization and setup."""

    def test_main_window_creation(self, qtbot, sample_config):
        """Test MainWindow can be instantiated."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        assert window is not None
        assert window.config == sample_config

    def test_main_window_title(self, qtbot, sample_config):
        """Test window title is set correctly."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        expected_title = f"{sample_config.app_name} v{sample_config.app_version}"
        assert window.windowTitle() == expected_title

    def test_main_window_geometry(self, qtbot, sample_config):
        """Test window geometry is set correctly."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        assert window.width() == sample_config.window_width
        assert window.height() == sample_config.window_height

    def test_main_window_has_web_view(self, qtbot, sample_config):
        """Test MainWindow has web_view attribute."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        assert hasattr(window, "web_view")
        assert window.web_view is not None

    def test_main_window_has_drag_interceptor(self, qtbot, sample_config):
        """Test MainWindow has drag_interceptor attribute."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        assert hasattr(window, "drag_interceptor")
        assert window.drag_interceptor is not None


class TestMainWindowNavigation:
    """Test navigation toolbar and functionality."""

    def test_navigation_toolbar_created(self, qtbot, sample_config):
        """Test navigation toolbar is created."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        toolbars = window.findChildren(QToolBar)
        assert len(toolbars) > 0

    def test_navigation_toolbar_not_movable(self, qtbot, sample_config):
        """Test navigation toolbar is not movable (locked for Kiosk-mode)."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        toolbar = window.findChild(QToolBar)
        assert toolbar is not None
        assert not toolbar.isMovable()

    def test_navigate_home(self, qtbot, sample_config):
        """Test home button navigation."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        with patch.object(window.web_view, "load") as mock_load:
            window._navigate_home()
            mock_load.assert_called_once()

    def test_navigate_home_with_http_url(self, qtbot, tmp_path):
        """Test home navigation with HTTP URL."""
        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],
            webapp_url="http://localhost:8000",
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        window = MainWindow(config)
        qtbot.addWidget(window)

        with patch.object(window.web_view, "load") as mock_load:
            window._navigate_home()

            # Verify load was called with HTTP URL
            call_args = mock_load.call_args
            url = call_args[0][0]
            assert url.scheme() == "http"

    def test_navigate_home_with_file_url(self, qtbot, sample_config):
        """Test home navigation with file:// URL."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        with patch.object(window.web_view, "load") as mock_load:
            window._navigate_home()

            call_args = mock_load.call_args
            url = call_args[0][0]
            assert url.scheme() == "file"


class TestMainWindowWebAppLoading:
    """Test web application loading."""

    def test_load_local_webapp_file(self, qtbot, sample_config):
        """Test loading local webapp file."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Window should load without errors
        assert window.web_view is not None

    def test_load_remote_webapp_url(self, qtbot, tmp_path):
        """Test loading remote webapp URL."""
        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=["localhost"],
            webapp_url="http://localhost:3000",
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        window = MainWindow(config)
        qtbot.addWidget(window)

        assert window.web_view is not None

    def test_load_nonexistent_file_shows_welcome_page(self, qtbot, tmp_path):
        """Test loading nonexistent file shows welcome page HTML."""
        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],
            webapp_url="/nonexistent/file.html",
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        with patch.object(config, "webapp_url", "/nonexistent/file.html"):
            window = MainWindow(config)
            qtbot.addWidget(window)

            with patch.object(
                window.web_view, "setHtml"
            ) as mock_set_html:
                window._load_webapp()
                mock_set_html.assert_called_once()

                # Verify welcome page is shown instead of error
                call_args = mock_set_html.call_args[0][0]
                assert "WebDrop Bridge" in call_args
                assert "Application Ready" in call_args


class TestMainWindowDragIntegration:
    """Test drag-and-drop integration."""

    def test_drag_interceptor_validator_set(self, qtbot, sample_config):
        """Test drag interceptor validator is configured."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        assert window.drag_interceptor._validator is not None

    def test_drag_interceptor_signals_connected(self, qtbot, sample_config):
        """Test drag interceptor signals are connected."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Signals should be connected
        assert window.drag_interceptor.drag_started is not None
        assert window.drag_interceptor.drag_failed is not None

    def test_handle_drag_delegates_to_interceptor(
        self, qtbot, sample_config, tmp_path
    ):
        """Test drag handling delegates to interceptor."""
        from PySide6.QtCore import QCoreApplication
        
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Create test file
        test_file = sample_config.allowed_roots[0] / "test.txt"
        test_file.write_text("test")

        with patch.object(
            window.drag_interceptor, "handle_drag"
        ) as mock_drag:
            mock_drag.return_value = True
            # Call through bridge
            window._drag_bridge.start_file_drag(str(test_file))
            
            # Process deferred QTimer.singleShot(0, ...) call
            QCoreApplication.processEvents()

            mock_drag.assert_called_once_with(str(test_file))

    def test_on_drag_started_called(self, qtbot, sample_config):
        """Test _on_drag_started handler can be called."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Should not raise - new signature has source and local_path
        window._on_drag_started("https://example.com/file.png", "/local/path/file.png")

    def test_on_drag_failed_called(self, qtbot, sample_config):
        """Test _on_drag_failed handler can be called."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Should not raise - new signature has source and error
        window._on_drag_failed("https://example.com/file.png", "Test error message")


class TestMainWindowURLWhitelist:
    """Test URL whitelisting integration."""

    def test_restricted_web_view_receives_allowed_urls(
        self, qtbot, sample_config
    ):
        """Test RestrictedWebEngineView receives allowed URLs from config."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # web_view should have allowed_urls configured
        assert window.web_view.allowed_urls == sample_config.allowed_urls

    def test_empty_allowed_urls_list(self, qtbot, tmp_path):
        """Test with empty allowed URLs (no restriction)."""
        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],  # Empty = no restriction
            webapp_url="http://localhost",
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        window = MainWindow(config)
        qtbot.addWidget(window)

        assert window.web_view.allowed_urls == []


class TestMainWindowSignals:
    """Test signal connections."""

    def test_drag_started_signal_connection(self, qtbot, sample_config):
        """Test drag_started signal is connected to handler."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        with patch.object(window, "_on_drag_started") as mock_handler:
            window.drag_interceptor.drag_started.emit(["/path/to/file"])
            mock_handler.assert_called_once()

    def test_drag_failed_signal_connection(self, qtbot, sample_config):
        """Test drag_failed signal is connected to handler."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        with patch.object(window, "_on_drag_failed") as mock_handler:
            window.drag_interceptor.drag_failed.emit("Error message")
            mock_handler.assert_called_once()


class TestMainWindowMenuBar:
    """Test toolbar help actions integration."""

    def test_navigation_toolbar_created(self, qtbot, sample_config):
        """Test navigation toolbar is created with help buttons."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        # Check that toolbar exists
        assert len(window.findChildren(QToolBar)) > 0
        toolbar = window.findChildren(QToolBar)[0]
        assert toolbar is not None

    def test_window_has_check_for_updates_signal(self, qtbot, sample_config):
        """Test window has check_for_updates signal."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        # Test that signal exists
        assert hasattr(window, "check_for_updates")
        
        # Test that signal is callable (can be emitted)
        assert callable(window.check_for_updates.emit)

    def test_on_check_for_updates_method_exists(self, qtbot, sample_config):
        """Test _on_manual_check_for_updates method exists."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        # Test that the method exists
        assert hasattr(window, "_on_manual_check_for_updates")
        assert callable(window._on_manual_check_for_updates)

    def test_show_about_dialog_method_exists(self, qtbot, sample_config):
        """Test _show_about_dialog method exists."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        # Test that the method exists
        assert hasattr(window, "_show_about_dialog")
        assert callable(window._show_about_dialog)


class TestMainWindowStatusBar:
    """Test status bar and update status."""

    def test_status_bar_created(self, qtbot, sample_config):
        """Test status bar is created."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        assert window.statusBar() is not None
        assert hasattr(window, "status_bar")

    def test_update_status_label_created(self, qtbot, sample_config):
        """Test update status label exists."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        assert hasattr(window, "update_status_label")
        assert window.update_status_label is not None

    def test_set_update_status_text_only(self, qtbot, sample_config):
        """Test setting update status with text only."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Checking for updates")
        assert "Checking for updates" in window.update_status_label.text()

    def test_set_update_status_with_emoji(self, qtbot, sample_config):
        """Test setting update status with emoji."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Checking", emoji="🔄")
        assert "🔄" in window.update_status_label.text()
        assert "Checking" in window.update_status_label.text()

    def test_set_update_status_checking(self, qtbot, sample_config):
        """Test checking for updates status."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Checking for updates", emoji="🔄")
        assert "🔄" in window.update_status_label.text()

    def test_set_update_status_available(self, qtbot, sample_config):
        """Test update available status."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Update available v0.0.2", emoji="✅")
        assert "✅" in window.update_status_label.text()

    def test_set_update_status_downloading(self, qtbot, sample_config):
        """Test downloading status."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Downloading update", emoji="⬇️")
        assert "⬇️" in window.update_status_label.text()

    def test_set_update_status_error(self, qtbot, sample_config):
        """Test error status."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)
        
        window.set_update_status("Update check failed", emoji="⚠️")
        assert "⚠️" in window.update_status_label.text()


class TestMainWindowStylesheet:
    """Test stylesheet application."""

    def test_stylesheet_loading_gracefully_handles_missing_file(
        self, qtbot, sample_config
    ):
        """Test missing stylesheet doesn't crash application."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Should not raise even if stylesheet missing
        window._apply_stylesheet()

    def test_stylesheet_loading_with_nonexistent_file(
        self, qtbot, sample_config
    ):
        """Test stylesheet loading with nonexistent file path."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        with patch("builtins.open", side_effect=OSError("File not found")):
            # Should handle gracefully
            window._apply_stylesheet()


class TestMainWindowCloseEvent:
    """Test window close handling."""

    def test_close_event_accepted(self, qtbot, sample_config):
        """Test close event is accepted."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        from PySide6.QtGui import QCloseEvent

        event = QCloseEvent()
        window.closeEvent(event)

        assert event.isAccepted()


class TestMainWindowIntegration:
    """Integration tests for MainWindow with all components."""

    def test_full_initialization_flow(self, qtbot, sample_config):
        """Test complete initialization flow."""
        window = MainWindow(sample_config)
        qtbot.addWidget(window)

        # Verify all components initialized
        assert window.web_view is not None
        assert window.drag_interceptor is not None
        assert window.config == sample_config

        # Verify toolbar exists
        toolbars = window.findChildren(QToolBar)
        assert len(toolbars) > 0

    def test_window_with_multiple_allowed_roots(self, qtbot, tmp_path):
        """Test MainWindow with multiple allowed root directories."""
        root1 = tmp_path / "root1"
        root2 = tmp_path / "root2"
        root1.mkdir()
        root2.mkdir()

        webapp_file = tmp_path / "index.html"
        webapp_file.write_text("<html></html>")

        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[root1, root2],
            allowed_urls=[],
            webapp_url=str(webapp_file),
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        window = MainWindow(config)
        qtbot.addWidget(window)

        # Verify validator has both roots
        assert window.drag_interceptor._validator is not None
        assert len(
            window.drag_interceptor._validator.allowed_roots
        ) == 2

    def test_window_with_url_whitelist(self, qtbot, tmp_path):
        """Test MainWindow respects URL whitelist."""
        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=["*.example.com", "localhost"],
            webapp_url="http://localhost",
            window_width=800,
            window_height=600,
            enable_logging=False,
        )

        window = MainWindow(config)
        qtbot.addWidget(window)

        # Verify whitelist is set
        assert window.web_view.allowed_urls == ["*.example.com", "localhost"]
