"""Tests for library/download_management/failure_classifier.py."""

from datetime import timedelta, datetime, UTC


class TestBaseFailure:
    """Tests for BaseFailure class."""

    def test_stores_error_type(self):
        """Test that error_type is stored."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        # Create a concrete subclass for testing
        class TestFailure(BaseFailure):
            pass

        failure = TestFailure("test_error", "Test message", timedelta(hours=1))
        assert failure.error_type == "test_error"

    def test_stores_message(self):
        """Test that message is stored."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        class TestFailure(BaseFailure):
            pass

        failure = TestFailure("error", "Custom message", timedelta(hours=1))
        assert failure.message == "Custom message"

    def test_stores_retry_after(self):
        """Test that retry_after is stored."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        class TestFailure(BaseFailure):
            pass

        retry = timedelta(hours=2)
        failure = TestFailure("error", "message", retry)
        assert failure.retry_after == retry

    def test_sets_created_at(self):
        """Test that created_at is set to current time."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        class TestFailure(BaseFailure):
            pass

        before = datetime.now(UTC)
        failure = TestFailure("error", "message", timedelta(hours=1))
        after = datetime.now(UTC)

        assert before <= failure.created_at <= after

    def test_is_permanent_returns_true_when_no_retry(self):
        """Test that is_permanent returns True when retry_after is None."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        class TestFailure(BaseFailure):
            pass

        failure = TestFailure("error", "message", None)
        assert failure.is_permanent() is True

    def test_is_permanent_returns_false_when_has_retry(self):
        """Test that is_permanent returns False when retry_after is set."""
        from local_deep_research.library.download_management.failure_classifier import (
            BaseFailure,
        )

        class TestFailure(BaseFailure):
            pass

        failure = TestFailure("error", "message", timedelta(hours=1))
        assert failure.is_permanent() is False


class TestPermanentFailure:
    """Tests for PermanentFailure class."""

    def test_is_always_permanent(self):
        """Test that PermanentFailure is always permanent."""
        from local_deep_research.library.download_management.failure_classifier import (
            PermanentFailure,
        )

        failure = PermanentFailure("not_found", "Resource not found")
        assert failure.is_permanent() is True

    def test_retry_after_is_none(self):
        """Test that retry_after is always None."""
        from local_deep_research.library.download_management.failure_classifier import (
            PermanentFailure,
        )

        failure = PermanentFailure("forbidden", "Access forbidden")
        assert failure.retry_after is None


class TestTemporaryFailure:
    """Tests for TemporaryFailure class."""

    def test_is_not_permanent(self):
        """Test that TemporaryFailure is not permanent."""
        from local_deep_research.library.download_management.failure_classifier import (
            TemporaryFailure,
        )

        failure = TemporaryFailure(
            "timeout", "Request timed out", timedelta(minutes=30)
        )
        assert failure.is_permanent() is False

    def test_stores_cooldown(self):
        """Test that cooldown is stored as retry_after."""
        from local_deep_research.library.download_management.failure_classifier import (
            TemporaryFailure,
        )

        cooldown = timedelta(hours=2)
        failure = TemporaryFailure("error", "message", cooldown)
        assert failure.retry_after == cooldown


class TestRateLimitFailure:
    """Tests for RateLimitFailure class."""

    def test_stores_domain(self):
        """Test that domain is stored."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("arxiv.org")
        assert failure.domain == "arxiv.org"

    def test_uses_domain_specific_cooldown_for_arxiv(self):
        """Test that arxiv.org gets 6 hour cooldown."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("arxiv.org")
        assert failure.retry_after == timedelta(hours=6)

    def test_uses_domain_specific_cooldown_for_pubmed(self):
        """Test that pubmed gets 2 hour cooldown."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("pubmed.ncbi.nlm.nih.gov")
        assert failure.retry_after == timedelta(hours=2)

    def test_uses_default_cooldown_for_unknown_domain(self):
        """Test that unknown domains get 1 hour cooldown."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("unknown-domain.com")
        assert failure.retry_after == timedelta(hours=1)

    def test_includes_details_in_message(self):
        """Test that details are included in message."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("example.com", "Too many requests")
        assert "Too many requests" in failure.message

    def test_error_type_is_rate_limited(self):
        """Test that error_type is rate_limited."""
        from local_deep_research.library.download_management.failure_classifier import (
            RateLimitFailure,
        )

        failure = RateLimitFailure("example.com")
        assert failure.error_type == "rate_limited"


class TestFailureClassifier:
    """Tests for FailureClassifier class."""

    def test_404_returns_permanent_failure(self):
        """Test that 404 status code returns permanent failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            PermanentFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure("error", status_code=404)

        assert isinstance(result, PermanentFailure)
        assert result.error_type == "not_found"

    def test_403_returns_permanent_failure(self):
        """Test that 403 status code returns permanent failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            PermanentFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure("error", status_code=403)

        assert isinstance(result, PermanentFailure)
        assert result.error_type == "forbidden"

    def test_410_returns_permanent_failure(self):
        """Test that 410 status code returns permanent failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            PermanentFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure("error", status_code=410)

        assert isinstance(result, PermanentFailure)
        assert result.error_type == "gone"

    def test_429_returns_rate_limit_failure(self):
        """Test that 429 status code returns rate limit failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            RateLimitFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure(
            "error", status_code=429, url="https://example.com/resource"
        )

        assert isinstance(result, RateLimitFailure)

    def test_503_returns_temporary_failure(self):
        """Test that 503 status code returns temporary failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            TemporaryFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure("error", status_code=503)

        assert isinstance(result, TemporaryFailure)
        assert result.error_type == "server_error"

    def test_recaptcha_in_details_returns_temporary_failure(self):
        """Test that reCAPTCHA in details returns 3-day cooldown."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            TemporaryFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure(
            "arxiv_error", details="reCAPTCHA verification required"
        )

        assert isinstance(result, TemporaryFailure)
        assert result.retry_after == timedelta(days=3)

    def test_timeout_returns_temporary_failure(self):
        """Test that timeout error returns temporary failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            TemporaryFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure(
            "TimeoutError", details="Request timed out"
        )

        assert isinstance(result, TemporaryFailure)
        assert result.error_type == "timeout"
        assert result.retry_after == timedelta(minutes=30)

    def test_network_error_returns_temporary_failure(self):
        """Test that network error returns temporary failure."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            TemporaryFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure(
            "ConnectionError", details="Network unreachable"
        )

        assert isinstance(result, TemporaryFailure)
        assert result.error_type == "network_error"

    def test_unknown_error_returns_temporary_failure(self):
        """Test that unknown error returns temporary failure with 1 hour cooldown."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
            TemporaryFailure,
        )

        classifier = FailureClassifier()
        result = classifier.classify_failure(
            "SomeRandomError", details="Something happened"
        )

        assert isinstance(result, TemporaryFailure)
        assert result.error_type == "unknown_error"
        assert result.retry_after == timedelta(hours=1)

    def test_classify_from_exception(self):
        """Test classify_from_exception method."""
        from local_deep_research.library.download_management.failure_classifier import (
            FailureClassifier,
        )

        classifier = FailureClassifier()
        exception = TimeoutError("Connection timed out")

        result = classifier.classify_from_exception(exception)

        assert result.error_type == "timeout"
