from govcrawler.fetcher.throttle import HostThrottle
from govcrawler.fetcher import throttle


class FakeClock:
    def __init__(self):
        self.t = 1000.0
        self.slept = []

    def now(self):
        return self.t

    def sleep(self, s):
        self.slept.append(s)
        self.t += s


def test_first_call_no_wait():
    c = FakeClock()
    t = HostThrottle(interval_s=5.0, jitter_pct=0.0)
    slept = t.wait("https://a.com/x", sleep=c.sleep, now=c.now)
    assert slept == 0.0


def test_second_call_same_host_waits_at_least_interval():
    c = FakeClock()
    t = HostThrottle(interval_s=5.0, jitter_pct=0.0)
    t.wait("https://a.com/x", sleep=c.sleep, now=c.now)
    c.t += 1.0
    t.wait("https://a.com/y", sleep=c.sleep, now=c.now)
    assert sum(c.slept) >= 4.0


def test_different_host_no_wait():
    c = FakeClock()
    t = HostThrottle(interval_s=5.0, jitter_pct=0.0)
    t.wait("https://a.com/x", sleep=c.sleep, now=c.now)
    slept = t.wait("https://b.com/x", sleep=c.sleep, now=c.now)
    assert slept == 0.0


def test_positive_jitter_never_shortens_interval(monkeypatch):
    c = FakeClock()
    calls = []

    def fake_uniform(lo, hi):
        calls.append((lo, hi))
        return hi

    monkeypatch.setattr(throttle.random, "uniform", fake_uniform)
    t = HostThrottle(interval_s=10.0, jitter_pct=0.30)
    t.wait("https://a.com/x", sleep=c.sleep, now=c.now)
    c.t += 1.0

    slept = t.wait("https://a.com/y", sleep=c.sleep, now=c.now)

    assert calls == [(0.0, 0.30)]
    assert slept == 12.0


def test_absolute_jitter_adds_positive_window(monkeypatch):
    c = FakeClock()
    calls = []

    def fake_uniform(lo, hi):
        calls.append((lo, hi))
        return hi

    monkeypatch.setattr(throttle.random, "uniform", fake_uniform)
    t = HostThrottle(interval_s=30.0, jitter_s=10.0)
    t.wait("https://a.com/x", sleep=c.sleep, now=c.now)
    c.t += 2.0

    slept = t.wait("https://a.com/y", sleep=c.sleep, now=c.now)

    assert calls == [(0.0, 10.0)]
    assert slept == 38.0
