from datetime import timedelta

from yslow.models import Issue, IssueRecord, ProbeResult, Severity

from .conftest import T0, make_check


def test_stats_basic():
    r = ProbeResult(
        host="1.1.1.1", label="test", sent=5, lost=0, rtts=[10, 20, 30, 40, 50]
    )
    assert r.avg == 30.0
    assert r.min == 10.0
    assert r.max == 50.0
    assert r.loss_pct == 0.0
    assert r.reachable is True


def test_stats_with_loss():
    r = ProbeResult(host="1.1.1.1", label="test", sent=5, lost=2, rtts=[10, 20, 30])
    assert r.avg == 20.0
    assert r.loss_pct == 40.0


def test_unreachable():
    r = ProbeResult(host="1.1.1.1", label="test", sent=5, lost=5, rtts=[])
    assert r.reachable is False
    assert r.avg is None
    assert r.min is None
    assert r.max is None
    assert r.jitter is None
    assert r.loss_pct == 100.0


def test_jitter_single_sample():
    r = ProbeResult(host="1.1.1.1", label="test", sent=1, lost=0, rtts=[10.0])
    assert r.jitter == 0.0


def test_jitter_stable():
    r = ProbeResult(
        host="1.1.1.1", label="test", sent=3, lost=0, rtts=[10.0, 10.0, 10.0]
    )
    assert r.jitter == 0.0


def test_jitter_varies():
    r = ProbeResult(host="1.1.1.1", label="test", sent=2, lost=0, rtts=[10.0, 20.0])
    # stdev of [10, 20] with sample stdev (n-1) = ~7.07
    assert r.jitter is not None and abs(r.jitter - 7.07) < 0.1


def test_zero_sent():
    r = ProbeResult(host="1.1.1.1", label="test", sent=0, lost=0, rtts=[])
    assert r.loss_pct == 0.0


class TestCheckResultHealthy:
    def test_healthy_when_no_issues(self):
        r = make_check(healthy=True)
        assert r.healthy is True

    def test_unhealthy_when_issues(self):
        r = make_check(healthy=False)
        assert r.healthy is False


class TestIssueHistory:
    def test_no_issues(self):
        results = [make_check(healthy=True)]
        assert IssueRecord.from_results(results) == []

    def test_active_issue(self):
        results = [make_check(healthy=False, timestamp=T0 + timedelta(seconds=10))]
        history = IssueRecord.from_results(results)
        assert len(history) == 1
        assert history[0].kind == "test-problem"
        assert history[0].source == "LAN"
        assert history[0].name == "test problem"
        assert history[0].cause == "test cause"
        assert history[0].count == 1
        assert history[0].active is True

    def test_resolved_issue(self):
        results = [
            make_check(healthy=False, timestamp=T0 + timedelta(seconds=10)),
            make_check(healthy=True, timestamp=T0 + timedelta(seconds=40)),
        ]
        history = IssueRecord.from_results(results)
        assert len(history) == 1
        assert history[0].active is False

    def test_counts_accumulate(self):
        results = [
            make_check(healthy=False, timestamp=T0 + timedelta(seconds=10)),
            make_check(healthy=True, timestamp=T0 + timedelta(seconds=40)),
            make_check(healthy=False, timestamp=T0 + timedelta(seconds=70)),
        ]
        history = IssueRecord.from_results(results)
        assert history[0].count == 2
        assert history[0].active is True

    def test_multiple_kinds(self):
        results = [
            make_check(
                issues=[
                    Issue(Severity.ERROR, "problem-a", source="LAN", name="Problem A"),
                    Issue(Severity.ERROR, "problem-b", source="ISP", name="Problem B"),
                ],
                timestamp=T0 + timedelta(seconds=10),
            ),
            make_check(
                issues=[
                    Issue(Severity.ERROR, "problem-a", source="LAN", name="Problem A"),
                ],
                timestamp=T0 + timedelta(seconds=40),
            ),
        ]
        history = IssueRecord.from_results(results)
        assert len(history) == 2
        by_kind = {r.kind: r for r in history}
        assert by_kind["problem-a"].count == 2
        assert by_kind["problem-a"].active is True
        assert by_kind["problem-b"].count == 1
        assert by_kind["problem-b"].active is False
