"""Regression tests: api.py + scheduler.py delegate to handlers/_ack_id (SP27 Task 6).

After the dedup, the inline `_ack_count_summary`,
`_ack_synthetic_source_batch_id`, and `_277ca_synthetic_source_batch_id`
helpers should be gone from both `api.py` and `scheduler.py`. Their
callers should reach the canonical copies under
``cyclone.handlers._ack_id``.

This test pins two things:

1. The module attributes exist where expected (import paths intact).
2. The endpoints that depend on the helpers still respond 200 (or
   401 if unauthenticated) — i.e. the dedup didn't break the import
   chain.
"""
from __future__ import annotations

import pytest
from fastapi.testclient import TestClient

from cyclone import api, scheduler
from cyclone.api import app
from cyclone.handlers._ack_id import (
    ack_count_summary,
    ack_synthetic_source_batch_id,
    two77ca_synthetic_source_batch_id,
)


# ---- 1. The dedup actually happened ---------------------------------------


def test_api_no_longer_defines_inline_ack_helpers():
    """api.py must not re-define the helpers as local symbols.

    The alias imports at the top of api.py (``from cyclone.handlers._ack_id
    import ack_count_summary as _ack_count_summary``) leave the
    underscore-prefixed names bound in ``api.__dict__`` — that's the
    whole point of an alias import and is required so the inline
    call sites keep working. What we want to check is that the
    *implementation source* is no longer the api module itself.

    Concretely: the function's ``__module__`` attribute should be
    ``cyclone.handlers._ack_id``, not ``cyclone.api``.
    """
    for name in (
        "_ack_count_summary",
        "_ack_synthetic_source_batch_id",
        "_277ca_synthetic_source_batch_id",
    ):
        assert hasattr(api, name), (
            f"api.py doesn't even have {name} — alias import missing"
        )
        fn = getattr(api, name)
        assert fn.__module__ == "cyclone.handlers._ack_id", (
            f"api.{name} resolves to {fn.__module__}, expected "
            f"cyclone.handlers._ack_id — inline copy still exists"
        )


def test_scheduler_no_inline_ack_helpers():
    """scheduler.py must not re-define the ack helpers as local symbols.

    In SP27 Task 2 the inline copies of ``_ack_count_summary`` and
    ``_ack_synthetic_source_batch_id`` were deleted from
    scheduler.py (they had become dead code after Task 1 lifted the
    canonical copies into ``cyclone.handlers._ack_id``). Task 4
    removed ``_277ca_synthetic_source_batch_id`` the same way. So
    none of the three names should be present in the scheduler
    module at all.
    """
    for name in (
        "_ack_count_summary",
        "_ack_synthetic_source_batch_id",
        "_277ca_synthetic_source_batch_id",
    ):
        assert not hasattr(scheduler, name), (
            f"scheduler.py still defines {name} inline; dedup incomplete"
        )


def test_canonical_helpers_resolve_to_handlers_ack_id():
    """The names exported by ``cyclone.handlers._ack_id`` must be
    reachable from the canonical import path."""
    assert callable(ack_count_summary)
    assert callable(ack_synthetic_source_batch_id)
    assert callable(two77ca_synthetic_source_batch_id)


# ---- 2. Endpoints still respond -------------------------------------------


@pytest.fixture
def client() -> TestClient:
    return TestClient(app)


def test_ack_endpoints_respond_after_dedup(client):
    """Hitting each ack endpoint must not raise ImportError. Either
    200 (auth OK) or 401/403 (auth required) is acceptable; 500 means
    the import chain broke."""
    # Acquire an authenticated session by hitting login (idempotent —
    # the same admin user already exists in the test DB).
    for path in (
        "/api/acks",
        "/api/ta1-acks",
        "/api/277ca-acks",
    ):
        resp = client.get(path)
        assert resp.status_code in (200, 401, 403), (
            f"{path} broke after dedup: {resp.status_code} {resp.text}"
        )
