import asyncio
import json
import sqlite3

import httpx
import pytest

from src import main
from src.live_snapshot_store import LiveSnapshotStore


@pytest.fixture(autouse=True)
def reset_live_snapshot_task(tmp_path, monkeypatch):
    monkeypatch.setattr(
        main,
        "_live_snapshot_store",
        LiveSnapshotStore(tmp_path / "live.sqlite3", clock=lambda: main._live_snapshot_clock()),
    )
    main._live_snapshot_task = None
    main._live_snapshot_value = None
    main._live_snapshot_created_at = None
    main._live_section_created_at = {
        section: None for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_section_failure_count = {
        section: 0 for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_section_retry_at = {
        section: None for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_snapshot_refreshing_sections = set()
    main._live_section_revisions = {
        section: 0 for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    yield
    main._live_snapshot_task = None
    main._live_snapshot_value = None
    main._live_snapshot_created_at = None
    main._live_section_created_at = {
        section: None for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_section_failure_count = {
        section: 0 for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_section_retry_at = {
        section: None for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_snapshot_refreshing_sections = set()
    main._live_section_revisions = {
        section: 0 for section in main.LIVE_SNAPSHOT_SECTIONS
    }


def payload(response):
    return json.loads(response.body)


@pytest.mark.anyio
async def test_live_snapshot_fetches_user_once_and_updates_work_and_activity(monkeypatch):
    calls = {"user": 0}

    async def user():
        calls["user"] += 1
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    async def events(authenticated_user):
        assert authenticated_user["login"] == "timmy"
        return [{"type": "push"}]

    async def updates():
        return {
            "items": [{"id": 42, "title": "Mentioned you"}],
            "page": 1,
            "total": 125,
            "has_more": True,
        }

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", updates)

    response = await main.live_snapshot()
    result = payload(response)

    assert calls["user"] == 1
    assert result["context"]["user"]["login"] == "timmy"
    assert result["events"] == [{"type": "push"}]
    assert result["notifications"] == [{"id": 42, "title": "Mentioned you"}]
    assert result["notification_pagination"] == {
        "page": 1, "total": 125, "has_more": True
    }
    assert result["sections"] == {
        "context": "fresh", "events": "fresh", "notifications": "fresh"
    }
    assert set(result["revisions"]) == {"context", "events", "notifications"}
    assert len(set(result["revisions"].values())) == 1
    assert result["revisions"]["context"].endswith(".1")


@pytest.mark.anyio
async def test_live_snapshot_omits_section_bodies_at_known_revisions(monkeypatch):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    async def events(_authenticated_user):
        return [{"type": "push"}]

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", empty)

    first = payload(await main.live_snapshot())
    second = payload(await main.live_snapshot(
        context_revision=first["revisions"]["context"],
        events_revision=first["revisions"]["events"],
        notifications_revision=first["revisions"]["notifications"],
    ))

    assert "context" not in second
    assert "events" not in second
    assert "notifications" not in second
    assert "notification_pagination" not in second
    assert second["sections"] == first["sections"]
    assert second["revisions"] == first["revisions"]
    assert "freshness" in second


@pytest.mark.anyio
async def test_warm_unchanged_polls_only_load_shared_metadata(monkeypatch):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", lambda _user: empty())
    monkeypatch.setattr(main, "notifications", empty)
    first = payload(await main.live_snapshot())
    full_load = main._live_snapshot_store.load
    metadata_load = main._live_snapshot_store.load_metadata
    calls = {"full": 0, "metadata": 0}

    def counted_full_load():
        calls["full"] += 1
        return full_load()

    def counted_metadata_load():
        calls["metadata"] += 1
        return metadata_load()

    monkeypatch.setattr(main._live_snapshot_store, "load", counted_full_load)
    monkeypatch.setattr(main._live_snapshot_store, "load_metadata", counted_metadata_load)

    for _ in range(10):
        response = await main.live_snapshot(
            context_revision=first["revisions"]["context"],
            events_revision=first["revisions"]["events"],
            notifications_revision=first["revisions"]["notifications"],
        )
        assert response.status_code == 200
        assert "context" not in payload(response)

    assert calls == {"full": 0, "metadata": 10}


@pytest.mark.anyio
async def test_live_snapshot_token_from_another_worker_never_suppresses_content(monkeypatch, tmp_path):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", lambda _user: empty())
    monkeypatch.setattr(main, "notifications", empty)
    worker_a = payload(await main.live_snapshot())
    worker_a_token = worker_a["revisions"]["context"]

    main._live_snapshot_value = None
    main._live_snapshot_created_at = None
    main._live_section_created_at = {
        section: None for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_section_revisions = {
        section: 0 for section in main.LIVE_SNAPSHOT_SECTIONS
    }
    main._live_snapshot_store = LiveSnapshotStore(
        tmp_path / "other-worker.sqlite3", clock=lambda: main._live_snapshot_clock()
    )

    worker_b = payload(await main.live_snapshot(context_revision=worker_a_token))

    assert worker_a_token.endswith(".1")
    assert worker_b["revisions"]["context"].endswith(".1")
    assert worker_b["revisions"]["context"] != worker_a_token
    assert worker_b["context"]["user"]["login"] == "timmy"


@pytest.mark.anyio
async def test_live_snapshot_rejects_malformed_revision_before_upstream_work(monkeypatch):
    async def unexpected_user():
        raise AssertionError("malformed revision reached upstream work")

    monkeypatch.setattr(main, "current_user", unexpected_user)
    transport = httpx.ASGITransport(app=main.app)

    async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
        response = await client.get("/api/v1/live?context_revision=not-a-token")

    assert response.status_code == 422


@pytest.mark.anyio
async def test_live_snapshot_keeps_fresh_context_when_activity_fails(monkeypatch):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    async def failing_events(authenticated_user):
        raise ConnectionError("secret upstream detail")

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", failing_events)
    monkeypatch.setattr(main, "notifications", empty)

    result = payload(await main.live_snapshot())

    assert result["context"]["user"]["login"] == "timmy"
    assert result["events"] is None
    assert result["sections"] == {
        "context": "fresh",
        "events": "temporarily unavailable",
        "notifications": "fresh",
    }
    assert "secret" not in json.dumps(result)


@pytest.mark.anyio
async def test_live_snapshot_keeps_work_and_activity_when_notifications_fail(monkeypatch):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    async def events(_authenticated_user):
        return [{"type": "push"}]

    async def failing_updates():
        raise ConnectionError("private notification failure")

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", failing_updates)

    result = payload(await main.live_snapshot())

    assert result["context"]["user"]["login"] == "timmy"
    assert result["events"] == [{"type": "push"}]
    assert result["notifications"] is None
    assert result["sections"]["notifications"] == "temporarily unavailable"
    assert "private" not in json.dumps(result)


@pytest.mark.anyio
async def test_live_snapshot_keeps_fresh_activity_when_work_fails(monkeypatch):
    async def user():
        return {"id": 1, "login": "timmy"}

    async def failing_repos():
        raise ConnectionError("work unavailable")

    async def empty():
        return []

    async def events(authenticated_user):
        return [{"type": "push"}]

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", failing_repos)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", empty)

    result = payload(await main.live_snapshot())

    assert result["context"] is None
    assert result["events"] == [{"type": "push"}]
    assert result["sections"] == {
        "context": "temporarily unavailable",
        "events": "fresh",
        "notifications": "fresh",
    }


@pytest.mark.anyio
async def test_live_snapshot_reuses_completed_snapshot_inside_freshness_window(monkeypatch):
    user_calls = 0
    user_started = asyncio.Event()
    release = asyncio.Event()

    async def user():
        nonlocal user_calls
        user_calls += 1
        user_started.set()
        return {"id": 1, "login": "timmy"}

    async def blocked_repos():
        await release.wait()
        return []

    async def empty():
        return []

    async def events(authenticated_user):
        return []

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", blocked_repos)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", empty)

    first = asyncio.create_task(main.live_snapshot())
    await user_started.wait()
    second = asyncio.create_task(main.live_snapshot())

    release.set()
    await asyncio.gather(first, second)
    await main.live_snapshot()

    assert user_calls == 1


@pytest.mark.anyio
async def test_stale_snapshot_returns_immediately_while_one_refresh_revalidates(monkeypatch):
    now = 100.0
    refresh_started = asyncio.Event()
    release_refresh = asyncio.Event()
    builds = 0

    async def snapshot(_sections=None):
        nonlocal builds
        builds += 1
        if builds == 2:
            refresh_started.set()
            await release_refresh.wait()
        return {
            "context": {"generation": builds},
            "events": [],
            "notifications": [],
            "sections": {},
        }

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "_build_live_snapshot", snapshot)

    first = payload(await main.live_snapshot())
    now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
    stale_request = asyncio.create_task(main.live_snapshot())
    await refresh_started.wait()
    await asyncio.sleep(0)
    returned_immediately = stale_request.done()
    release_refresh.set()
    stale = payload(await stale_request)

    assert returned_immediately is True
    assert first["context"]["generation"] == 1
    assert stale["context"]["generation"] == 1
    assert stale["freshness"]["stale"] is True
    assert stale["freshness"]["revalidating"] is True
    assert builds == 2


@pytest.mark.anyio
async def test_failed_revalidation_enters_cooldown_and_keeps_last_snapshot(monkeypatch):
    now = 100.0
    builds = 0

    async def snapshot(_sections=None):
        nonlocal builds
        builds += 1
        if builds > 1:
            raise ConnectionError("private upstream failure")
        return {
            "context": {"generation": 1},
            "events": [{"id": 1}],
            "notifications": [],
            "sections": {
                "context": "fresh",
                "events": "fresh",
                "notifications": "fresh",
            },
        }

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "_build_live_snapshot", snapshot)

    await main.live_snapshot()
    now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
    stale = payload(await main.live_snapshot())
    assert main._live_snapshot_task is not None
    await asyncio.gather(main._live_snapshot_task, return_exceptions=True)
    degraded = payload(await main.live_snapshot())

    assert stale["freshness"]["revalidating"] is True
    assert degraded["context"] == {"generation": 1}
    assert degraded["freshness"]["stale"] is True
    assert degraded["freshness"]["degraded"] is True
    assert degraded["freshness"]["last_refresh_failed"] is True
    assert degraded["freshness"]["revalidating"] is False
    assert degraded["freshness"]["retry_in_seconds"] > 0
    assert builds == 2
    assert "private" not in json.dumps(degraded)


@pytest.mark.anyio
async def test_partial_refresh_updates_fresh_sections_and_retains_failed_sections(monkeypatch):
    now = 100.0
    builds = 0

    async def snapshot(_sections=None):
        nonlocal builds
        builds += 1
        if builds == 1:
            return {
                "context": {"generation": 1},
                "events": [{"id": "last-known"}],
                "notifications": [{"id": 7}],
                "notification_pagination": {"page": 1, "total": 1, "has_more": False},
                "sections": {"context": "fresh", "events": "fresh", "notifications": "fresh"},
            }
        return {
            "context": {"generation": 2},
            "events": None,
            "notifications": [{"id": 8}],
            "notification_pagination": {"page": 1, "total": 1, "has_more": False},
            "sections": {
                "context": "fresh",
                "events": "temporarily unavailable",
                "notifications": "fresh",
            },
        }

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "_build_live_snapshot", snapshot)

    await main.live_snapshot()
    now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
    await main.live_snapshot()
    assert main._live_snapshot_task is not None
    await main._live_snapshot_task
    result = payload(await main.live_snapshot())

    assert result["context"] == {"generation": 2}
    assert result["events"] == [{"id": "last-known"}]
    assert result["notifications"] == [{"id": 8}]
    assert result["sections"] == {
        "context": "fresh",
        "events": "stale",
        "notifications": "fresh",
    }
    assert result["freshness"]["degraded"] is True
    assert result["freshness"]["revalidating"] is False


@pytest.mark.anyio
async def test_notification_cooldown_does_not_stop_due_work_and_activity_refreshes(monkeypatch):
    now = 100.0
    calls = {"context": 0, "events": 0, "notifications": 0}
    event_refresh_times = []
    notification_outage = False

    async def user():
        return {"id": 1, "login": "timmy"}

    async def work():
        calls["context"] += 1
        return []

    async def empty_work():
        return []

    async def events(_authenticated_user):
        calls["events"] += 1
        event_refresh_times.append(now)
        return [{"generation": calls["events"]}]

    async def updates():
        calls["notifications"] += 1
        if notification_outage:
            raise ConnectionError("notifications unavailable")
        return []

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", work)
    monkeypatch.setattr(main, "issues", empty_work)
    monkeypatch.setattr(main, "pull_requests", empty_work)
    monkeypatch.setattr(main, "activity_events", events)
    monkeypatch.setattr(main, "notifications", updates)

    await main.live_snapshot()
    notification_outage = True

    for elapsed in (
        main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1,
        main.LIVE_SNAPSHOT_RETRY_BASE_SECONDS,
    ):
        now += elapsed
        await main.live_snapshot()
        assert main._live_snapshot_task is not None
        await main._live_snapshot_task

    # Notification backoff is now 10 seconds. The healthy sections become due
    # one second before that cooldown expires and must refresh independently.
    now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
    response = payload(await main.live_snapshot())
    assert main._live_snapshot_task is not None
    await main._live_snapshot_task
    refreshed = payload(await main.live_snapshot())

    assert calls == {"context": 3, "events": 3, "notifications": 3}
    assert event_refresh_times == [100.0, 109.0, 123.0]
    assert response["freshness"]["sections"]["context"]["revalidating"] is True
    assert refreshed["events"] == [{"generation": 3}]
    assert refreshed["sections"]["notifications"] == "stale"
    assert refreshed["freshness"]["sections"]["notifications"]["retry_in_seconds"] == 1


@pytest.mark.anyio
async def test_retry_window_starts_one_refresh_and_success_clears_degraded_state(monkeypatch):
    now = 100.0
    builds = 0
    retry_started = asyncio.Event()
    release_retry = asyncio.Event()

    async def snapshot(_sections=None):
        nonlocal builds
        builds += 1
        if builds == 1:
            return {
                "context": {"generation": 1}, "events": [], "notifications": [],
                "sections": {"context": "fresh", "events": "fresh", "notifications": "fresh"},
            }
        if builds == 2:
            return {
                "context": None, "events": [], "notifications": [],
                "sections": {
                    "context": "temporarily unavailable",
                    "events": "fresh",
                    "notifications": "fresh",
                },
            }
        retry_started.set()
        await release_retry.wait()
        return {
            "context": {"generation": 3}, "events": [], "notifications": [],
            "sections": {"context": "fresh", "events": "fresh", "notifications": "fresh"},
        }

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "_build_live_snapshot", snapshot)

    await main.live_snapshot()
    now += main.LIVE_SNAPSHOT_FRESHNESS_SECONDS + 1
    await main.live_snapshot()
    assert main._live_snapshot_task is not None
    await main._live_snapshot_task
    now += main.LIVE_SNAPSHOT_RETRY_BASE_SECONDS

    first = asyncio.create_task(main.live_snapshot())
    second = asyncio.create_task(main.live_snapshot())
    await asyncio.wait_for(retry_started.wait(), timeout=1.0)
    assert builds == 3
    assert payload(await first)["freshness"]["revalidating"] is True
    assert payload(await second)["freshness"]["revalidating"] is True

    release_retry.set()
    refresh_task = main._live_snapshot_task
    assert refresh_task is not None
    await refresh_task
    recovered = payload(await main.live_snapshot())

    assert recovered["context"] == {"generation": 3}
    assert recovered["freshness"]["degraded"] is False
    assert recovered["freshness"]["last_refresh_failed"] is False
    assert recovered["freshness"]["retry_in_seconds"] == 0


@pytest.mark.anyio
async def test_cancelling_one_waiter_does_not_cancel_the_shared_snapshot(monkeypatch):
    started = asyncio.Event()
    release = asyncio.Event()
    snapshot_calls = 0

    async def blocked_snapshot(_sections=None):
        nonlocal snapshot_calls
        snapshot_calls += 1
        started.set()
        await release.wait()
        return {
            "context": {},
            "events": [],
            "notifications": [],
            "sections": {},
        }

    monkeypatch.setattr(main, "_build_live_snapshot", blocked_snapshot)

    disconnected = asyncio.create_task(main.live_snapshot())
    await started.wait()
    survivor = asyncio.create_task(main.live_snapshot())
    await asyncio.sleep(0)

    disconnected.cancel()
    with pytest.raises(asyncio.CancelledError):
        await disconnected

    assert main._live_snapshot_task is not None
    assert not main._live_snapshot_task.done()

    release.set()
    response = await survivor

    assert response.status_code == 200
    assert snapshot_calls == 1


@pytest.mark.anyio
async def test_shared_snapshot_deadline_cancels_upstream_work_for_all_waiters(monkeypatch):
    started = asyncio.Event()
    cancelled = asyncio.Event()

    async def snapshot_that_exceeds_deadline(_sections=None):
        started.set()
        try:
            await asyncio.Event().wait()
        finally:
            cancelled.set()

    monkeypatch.setattr(main, "_build_live_snapshot", snapshot_that_exceeds_deadline)
    monkeypatch.setattr(main, "CONTEXT_TIMEOUT_SECONDS", 0.01)

    first = asyncio.create_task(main.live_snapshot())
    await started.wait()
    second = asyncio.create_task(main.live_snapshot())

    try:
        responses = await asyncio.gather(first, second)
        await asyncio.wait_for(cancelled.wait(), timeout=0.1)

        assert [response.status_code for response in responses] == [503, 503]
        assert [payload(response)["error"] for response in responses] == [
            "Gitea live snapshot timed out after 0.01s",
            "Gitea live snapshot timed out after 0.01s",
        ]
    finally:
        task = main._live_snapshot_task
        if task is not None and not task.done():
            task.cancel()
            with pytest.raises(asyncio.CancelledError):
                await task


@pytest.mark.anyio
async def test_cold_refresh_cooldown_remains_a_retryable_503(monkeypatch):
    now = 100.0

    async def unavailable(_sections=None):
        raise ConnectionError("private upstream failure")

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: now)
    monkeypatch.setattr(main, "_build_live_snapshot", unavailable)

    first = await main.live_snapshot()
    second = await main.live_snapshot()

    assert first.status_code == 503
    assert second.status_code == 503
    assert payload(second) == {
        "error": "Gitea live snapshot is temporarily unavailable"
    }


@pytest.mark.anyio
async def test_cancelled_refresh_releases_shared_lease(monkeypatch):
    started = asyncio.Event()

    async def blocked(_sections=None):
        started.set()
        await asyncio.Event().wait()

    monkeypatch.setattr(main, "_build_live_snapshot", blocked)
    request = asyncio.create_task(main.live_snapshot())
    await started.wait()
    assert main._live_snapshot_task is not None

    main._live_snapshot_task.cancel()
    await asyncio.gather(request, main._live_snapshot_task, return_exceptions=True)

    replacement = main._live_snapshot_store.try_acquire_refresh(
        {"context"}, lease_seconds=1
    )
    assert replacement is not None


@pytest.mark.anyio
async def test_shared_store_outage_returns_retryable_503(monkeypatch):
    def unavailable():
        raise sqlite3.OperationalError("private database detail")

    monkeypatch.setattr(main._live_snapshot_store, "load", unavailable)

    response = await main.live_snapshot()

    assert response.status_code == 503
    assert response.headers["retry-after"] == "1"
    assert payload(response) == {
        "error": "Gitea live snapshot state is temporarily unavailable"
    }


@pytest.mark.anyio
async def test_independent_workers_reuse_shared_live_snapshot(monkeypatch, tmp_path):
    calls = 0

    async def user():
        nonlocal calls
        calls += 1
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", lambda _user: empty())
    monkeypatch.setattr(main, "notifications", empty)
    path = tmp_path / "worker-shared.sqlite3"
    monkeypatch.setattr(main, "_live_snapshot_store", LiveSnapshotStore(path, clock=lambda: 100.0))

    first = payload(await main.live_snapshot())
    main._live_snapshot_value = None
    main._live_snapshot_created_at = None
    main._live_section_created_at = {section: None for section in main.LIVE_SNAPSHOT_SECTIONS}
    main._live_snapshot_store = LiveSnapshotStore(path, clock=lambda: 100.0)
    second = payload(await main.live_snapshot())

    assert calls == 1
    assert second["context"] == first["context"]
    assert second["revisions"] == first["revisions"]


@pytest.mark.anyio
async def test_live_snapshot_persists_reboot_stable_wall_timestamps(monkeypatch, tmp_path):
    epoch = 1_700_000_000.0

    async def user():
        return {"id": 1, "login": "timmy"}

    async def empty():
        return []

    monkeypatch.setattr(main, "_live_snapshot_clock", lambda: epoch, raising=False)
    monkeypatch.setattr(
        main,
        "_live_snapshot_store",
        LiveSnapshotStore(tmp_path / "wall.sqlite3", clock=lambda: main._live_snapshot_clock()),
    )
    monkeypatch.setattr(main, "current_user", user)
    monkeypatch.setattr(main, "repos", empty)
    monkeypatch.setattr(main, "issues", empty)
    monkeypatch.setattr(main, "pull_requests", empty)
    monkeypatch.setattr(main, "activity_events", lambda _user: empty())
    monkeypatch.setattr(main, "notifications", empty)

    response = await main.live_snapshot()

    assert response.status_code == 200
    assert set(main._live_snapshot_store.load().created_at.values()) == {epoch}
