"""Unit tests for DragInterceptor component."""

from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from webdrop_bridge.config import Config
from webdrop_bridge.core.drag_interceptor import DragInterceptor


@pytest.fixture
def test_config(tmp_path):
    """Create test configuration."""
    return Config(
        app_name="Test App",
        app_version="1.0.0",
        log_level="INFO",
        log_file=None,
        allowed_roots=[tmp_path],
        allowed_urls=[],
        webapp_url="https://dev.agravity.io/",
        url_mappings=[],
        check_file_exists=True,
    )


class TestDragInterceptorInitialization:
    """Test DragInterceptor initialization and setup."""

    def test_drag_interceptor_creation(self, qtbot, test_config):
        """Test DragInterceptor can be instantiated."""
        interceptor = DragInterceptor(test_config)
        assert interceptor is not None
        assert interceptor._validator is not None
        assert interceptor._url_converter is not None

    def test_drag_interceptor_has_signals(self, qtbot, test_config):
        """Test DragInterceptor has required signals."""
        interceptor = DragInterceptor(test_config)
        assert hasattr(interceptor, "drag_started")
        assert hasattr(interceptor, "drag_failed")

    def test_set_validator(self, qtbot, test_config):
        """Test validator is set during construction."""
        interceptor = DragInterceptor(test_config)
        assert interceptor._validator is not None


class TestDragInterceptorValidation:
    """Test path validation in drag operations."""

    def test_handle_drag_empty_text(self, qtbot, test_config):
        """Test handling drag with empty text fails."""
        interceptor = DragInterceptor(test_config)
        with qtbot.waitSignal(interceptor.drag_failed):
            result = interceptor.handle_drag("")

        assert result is False

    def test_handle_drag_valid_file_path(self, qtbot, tmp_path):
        """Test handling drag with valid file path."""
        # Create a test file
        test_file = tmp_path / "test.txt"
        test_file.write_text("test content")

        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],
            webapp_url="https://test.com/",
            url_mappings=[],
            check_file_exists=True,
        )
        interceptor = DragInterceptor(config)

        # Mock the drag operation to simulate success
        with patch("webdrop_bridge.core.drag_interceptor.QDrag") as mock_drag:
            mock_drag_instance = MagicMock()
            # Simulate successful copy action
            from PySide6.QtCore import Qt
            mock_drag_instance.exec.return_value = Qt.DropAction.CopyAction
            mock_drag.return_value = mock_drag_instance

            result = interceptor.handle_drag(str(test_file))

        # Should return True on successful drag
        assert result is True

    def test_handle_drag_invalid_path(self, qtbot, test_config):
        """Test drag with invalid path fails."""
        interceptor = DragInterceptor(test_config)

        # Path outside allowed roots
        invalid_path = "/etc/passwd"

        with qtbot.waitSignal(interceptor.drag_failed):
            result = interceptor.handle_drag(invalid_path)

        assert result is False

    def test_handle_drag_nonexistent_file(self, qtbot, test_config, tmp_path):
        """Test drag with nonexistent file fails."""
        interceptor = DragInterceptor(test_config)

        nonexistent = tmp_path / "nonexistent.txt"

        with qtbot.waitSignal(interceptor.drag_failed):
            result = interceptor.handle_drag(str(nonexistent))

        assert result is False


class TestDragInterceptorAzureURL:
    """Test Azure URL to local path conversion in drag operations."""

    def test_handle_drag_azure_url(self, qtbot, tmp_path):
        """Test handling drag with Azure Blob Storage URL."""
        from webdrop_bridge.config import URLMapping

        # Create test file that would be the result
        test_file = tmp_path / "test.png"
        test_file.write_text("image data")

        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],
            webapp_url="https://test.com/",
            url_mappings=[
                URLMapping(
                    url_prefix="https://devagravitystg.file.core.windows.net/devagravitysync/",
                    local_path=str(tmp_path)
                )
            ],
            check_file_exists=True,
        )
        interceptor = DragInterceptor(config)

        # Azure URL
        azure_url = "https://devagravitystg.file.core.windows.net/devagravitysync/test.png"

        # Mock the drag operation
        with patch("webdrop_bridge.core.drag_interceptor.QDrag") as mock_drag:
            mock_drag_instance = MagicMock()
            from PySide6.QtCore import Qt
            mock_drag_instance.exec.return_value = Qt.DropAction.CopyAction
            mock_drag.return_value = mock_drag_instance

            result = interceptor.handle_drag(azure_url)

        assert result is True

    def test_handle_drag_unmapped_url(self, qtbot, test_config):
        """Test handling drag with unmapped URL fails."""
        interceptor = DragInterceptor(test_config)

        # URL with no mapping
        unmapped_url = "https://unknown.blob.core.windows.net/container/file.png"

        with qtbot.waitSignal(interceptor.drag_failed):
            result = interceptor.handle_drag(unmapped_url)

        assert result is False


class TestDragInterceptorSignals:
    """Test signal emission on drag operations."""

    def test_drag_started_signal_emitted(self, qtbot, tmp_path):
        """Test drag_started signal is emitted on success."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("content")

        config = Config(
            app_name="Test",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[tmp_path],
            allowed_urls=[],
            webapp_url="https://test.com/",
            url_mappings=[],
            check_file_exists=True,
        )
        interceptor = DragInterceptor(config)

        # Connect to signal manually
        signal_spy = []
        interceptor.drag_started.connect(lambda src, path: signal_spy.append((src, path)))

        from PySide6.QtCore import Qt
        with patch("webdrop_bridge.core.drag_interceptor.QDrag") as mock_drag:
            mock_drag_instance = MagicMock()
            mock_drag_instance.exec.return_value = Qt.DropAction.CopyAction
            mock_drag.return_value = mock_drag_instance

            result = interceptor.handle_drag(str(test_file))

        # Verify result and signal emission
        assert result is True
        assert len(signal_spy) == 1

    def test_drag_failed_signal_on_empty_text(self, qtbot, test_config):
        """Test drag_failed signal on empty text."""
        interceptor = DragInterceptor(test_config)

        # Connect to signal manually
        signal_spy = []
        interceptor.drag_failed.connect(lambda src, msg: signal_spy.append((src, msg)))

        result = interceptor.handle_drag("")

        # Verify result and signal emission
        assert result is False
        assert len(signal_spy) == 1
        assert "Empty" in signal_spy[0][1]

    def test_drag_failed_signal_on_validation_error(self, qtbot, test_config):
        """Test drag_failed signal on validation failure."""
        interceptor = DragInterceptor(test_config)

        # Connect to signal manually
        signal_spy = []
        interceptor.drag_failed.connect(lambda src, msg: signal_spy.append((src, msg)))

        result = interceptor.handle_drag("/invalid/path/file.txt")

        # Verify result and signal emission
        assert result is False
        assert len(signal_spy) == 1
