from yslow.diagnosis import _analyze_dns
from yslow.models import DnsResult, Severity


def _configured(server="10.0.0.1", label="ISP DNS", cached_ms=1.0, uncached_ms=50.0):
    return DnsResult(
        server=server,
        label=label,
        cached_ms=cached_ms,
        uncached_ms=uncached_ms,
        is_configured=True,
    )


def _public(server="1.1.1.1", label="Cloudflare DNS", cached_ms=9.0, uncached_ms=40.0):
    return DnsResult(
        server=server,
        label=label,
        cached_ms=cached_ms,
        uncached_ms=uncached_ms,
        is_configured=False,
    )


class TestAnalyzeDnsHealthy:
    def test_all_fast(self):
        results = [
            _configured(),
            _public(),
            _public("8.8.8.8", "Google DNS", 2.0, 60.0),
        ]
        issues, alerts = _analyze_dns(results)
        assert issues == []
        assert alerts == []

    def test_no_alerts_for_slow_public_resolvers(self):
        """Public resolvers with high cached times shouldn't trigger alerts."""
        results = [
            _configured(),
            _public("8.8.8.8", "Google DNS", 30.0, 60.0),
        ]
        issues, alerts = _analyze_dns(results)
        assert not any(a.host == "8.8.8.8" for a in alerts)


class TestAnalyzeDnsUncached:
    def test_warning_threshold(self):
        results = [_configured(uncached_ms=150.0)]
        issues, alerts = _analyze_dns(results)
        assert any(i.kind == "dns-uncached-slow" for i in issues)
        assert any(i.severity == Severity.WARNING for i in issues)
        assert any(
            a.metric == "dns-uncached" and a.severity == Severity.WARNING
            for a in alerts
        )

    def test_error_threshold(self):
        results = [_configured(uncached_ms=300.0)]
        issues, alerts = _analyze_dns(results)
        assert any(
            i.kind == "dns-uncached-slow" and i.severity == Severity.ERROR
            for i in issues
        )
        assert any(
            a.metric == "dns-uncached" and a.severity == Severity.ERROR for a in alerts
        )


class TestAnalyzeDnsComparison:
    def test_configured_slower_than_public(self):
        """Configured is >2x slower but under the absolute uncached threshold."""
        results = [
            _configured(uncached_ms=95.0),
            _public("1.1.1.1", "Cloudflare DNS", 9.0, 40.0),
        ]
        issues, _alerts = _analyze_dns(results)
        assert any(i.kind == "dns-slow-configured" for i in issues)
        slow = next(i for i in issues if i.kind == "dns-slow-configured")
        assert "Cloudflare" in slow.cause

    def test_not_flagged_when_close(self):
        results = [
            _configured(uncached_ms=70.0),
            _public("1.1.1.1", "Cloudflare DNS", 9.0, 60.0),
        ]
        issues, _alerts = _analyze_dns(results)
        assert not any(i.kind == "dns-slow-configured" for i in issues)

    def test_comparison_suppressed_when_already_flagged(self):
        """When configured is over the uncached threshold, don't also suggest switching."""
        results = [
            _configured(uncached_ms=200.0),
            _public("1.1.1.1", "Cloudflare DNS", 9.0, 40.0),
        ]
        issues, _alerts = _analyze_dns(results)
        assert any(i.kind == "dns-uncached-slow" for i in issues)
        assert not any(i.kind == "dns-slow-configured" for i in issues)

    def test_no_comparison_when_no_alternatives(self):
        """If all resolvers are configured (no public alternatives tested), skip comparison."""
        results = [_configured(uncached_ms=95.0)]
        issues, _alerts = _analyze_dns(results)
        assert not any(i.kind == "dns-slow-configured" for i in issues)


class TestAnalyzeDnsFailure:
    def test_resolver_unreachable(self):
        results = [
            _configured(cached_ms=None, uncached_ms=None),
        ]
        issues, _alerts = _analyze_dns(results)
        assert any("unreachable" in i.name for i in issues)
        assert issues[0].severity == Severity.ERROR

    def test_partial_failure(self):
        """Resolver that can cache but not resolve uncached is not flagged as failure."""
        results = [_configured(cached_ms=2.0, uncached_ms=None)]
        issues, _alerts = _analyze_dns(results)
        assert not any("unreachable" in i.name for i in issues)
