"""
Tests for utilities/url_utils.py

Tests cover:
- URL normalization
- Scheme handling
- Private IP detection
"""

import pytest
from unittest.mock import patch


class TestNormalizeUrl:
    """Tests for normalize_url function."""

    def test_normalize_url_with_http_scheme(self):
        """Test URL with http:// scheme is returned unchanged."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("http://example.com")
        assert result == "http://example.com"

    def test_normalize_url_with_https_scheme(self):
        """Test URL with https:// scheme is returned unchanged."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("https://example.com")
        assert result == "https://example.com"

    def test_normalize_url_with_http_scheme_and_port(self):
        """Test URL with http:// scheme and port is returned unchanged."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("http://example.com:8080")
        assert result == "http://example.com:8080"

    def test_normalize_url_empty_raises_error(self):
        """Test that empty URL raises ValueError."""
        from local_deep_research.utilities.url_utils import normalize_url

        with pytest.raises(ValueError) as exc_info:
            normalize_url("")
        assert "empty" in str(exc_info.value).lower()

    def test_normalize_url_strips_whitespace(self):
        """Test that whitespace is stripped."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("  http://example.com  ")
        assert result == "http://example.com"

    def test_normalize_url_malformed_http_colon(self):
        """Test URL with malformed http: (missing //) is fixed."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("http:example.com")
        assert result == "http://example.com"

    def test_normalize_url_malformed_https_colon(self):
        """Test URL with malformed https: (missing //) is fixed."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("https:example.com")
        assert result == "https://example.com"

    def test_normalize_url_localhost_gets_http(self):
        """Test that localhost gets http:// scheme."""
        from local_deep_research.utilities.url_utils import normalize_url

        with patch(
            "local_deep_research.utilities.url_utils.is_private_ip",
            return_value=True,
        ):
            result = normalize_url("localhost:8080")
            assert result == "http://localhost:8080"

    def test_normalize_url_external_gets_https(self):
        """Test that external hosts get https:// scheme."""
        from local_deep_research.utilities.url_utils import normalize_url

        with patch(
            "local_deep_research.utilities.url_utils.is_private_ip",
            return_value=False,
        ):
            result = normalize_url("example.com:443")
            assert result == "https://example.com:443"

    def test_normalize_url_double_slash_prefix(self):
        """Test URL starting with // has prefix removed."""
        from local_deep_research.utilities.url_utils import normalize_url

        with patch(
            "local_deep_research.utilities.url_utils.is_private_ip",
            return_value=False,
        ):
            result = normalize_url("//example.com")
            assert result == "https://example.com"

    def test_normalize_url_127_0_0_1(self):
        """Test that 127.0.0.1 gets http:// scheme."""
        from local_deep_research.utilities.url_utils import normalize_url

        with patch(
            "local_deep_research.utilities.url_utils.is_private_ip",
            return_value=True,
        ):
            result = normalize_url("127.0.0.1:11434")
            assert result == "http://127.0.0.1:11434"

    def test_normalize_url_preserves_path(self):
        """Test that URL path is preserved."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("http://example.com/api/v1/search")
        assert result == "http://example.com/api/v1/search"

    def test_normalize_url_preserves_query_string(self):
        """Test that query string is preserved."""
        from local_deep_research.utilities.url_utils import normalize_url

        result = normalize_url("http://example.com?q=test&page=1")
        assert result == "http://example.com?q=test&page=1"


class TestCanonicalUrlKey:
    """Tests for canonical_url_key — dedup key generation, NOT for display."""

    def setup_method(self):
        # lru_cache persists across tests; clear to keep each assertion
        # independent of prior test inputs.
        from local_deep_research.utilities.url_utils import canonical_url_key

        canonical_url_key.cache_clear()

    def test_empty_returns_empty(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert canonical_url_key("") == ""

    def test_lowercases_scheme_and_host_preserves_path_case(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("HTTPS://EXAMPLE.COM/Foo/Bar")
            == "https://example.com/Foo/Bar"
        )

    def test_strips_fragment(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("https://example.com/page#section")
            == "https://example.com/page"
        )

    def test_trailing_slash_normalized(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert canonical_url_key("https://example.com/p") == canonical_url_key(
            "https://example.com/p/"
        )
        # Root path '/' is preserved (not stripped to empty).
        assert canonical_url_key("https://example.com/").endswith("/")

    def test_strips_utm_and_common_trackers(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        url = (
            "https://example.com/p?"
            "utm_source=x&UTM_Medium=y&utm_campaign=z&"
            "fbclid=a&gclid=b&msclkid=c&yclid=d&dclid=e&gad_source=f&"
            "mc_eid=g&mc_cid=h&ref_src=i&igshid=j&_ga=k&_gl=l"
        )
        assert canonical_url_key(url) == "https://example.com/p"

    def test_keeps_non_tracking_query_params(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        # q, ref (GitHub branch), v (YouTube id), page, id are content-bearing.
        assert (
            canonical_url_key("https://github.com/o/r?ref=main&utm_source=x")
            == "https://github.com/o/r?ref=main"
        )
        assert (
            canonical_url_key(
                "https://www.youtube.com/watch?v=abc123&utm_source=x"
            )
            == "https://www.youtube.com/watch?v=abc123"
        )
        assert (
            canonical_url_key("https://example.com/p?q=hello&page=2")
            == "https://example.com/p?q=hello&page=2"
        )

    def test_strips_userinfo(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("https://user:pass@example.com/p")
            == "https://example.com/p"
        )
        # Userinfo without colon.
        assert (
            canonical_url_key("https://user@example.com/p")
            == "https://example.com/p"
        )

    def test_strips_default_ports(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("https://example.com:443/p")
            == "https://example.com/p"
        )
        assert (
            canonical_url_key("http://example.com:80/p")
            == "http://example.com/p"
        )

    def test_preserves_nondefault_port(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("https://example.com:8443/p")
            == "https://example.com:8443/p"
        )

    def test_ipv6_host_preserved(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key("https://[::1]:8443/page")
            == "https://[::1]:8443/page"
        )

    def test_invalid_url_returned_stripped(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert canonical_url_key("  not a url  ") == "not a url"

    def test_mailto_returns_stripped(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert canonical_url_key("mailto:foo@bar.com") == "mailto:foo@bar.com"

    def test_protocol_relative_returns_stripped(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        # Protocol-relative URL has no scheme — canonicalization is ambiguous,
        # so we fall back to the stripped input.
        assert canonical_url_key("//example.com/path") == "//example.com/path"

    def test_combined_normalization(self):
        from local_deep_research.utilities.url_utils import canonical_url_key

        assert (
            canonical_url_key(
                "HTTPS://User:Pass@Example.COM:443/Path/?utm_source=x&q=1#frag"
            )
            == "https://example.com/Path?q=1"
        )
