"""Regression coverage for GitHub Actions codegen callback authentication."""

from types import SimpleNamespace
from unittest.mock import AsyncMock
from uuid import uuid4

import pytest
import structlog.testing
from src.core.exceptions import ForbiddenError
from src.core.security import jwt as jwt_security
from src.domain.devices import dependencies


def test_actions_callback_token_accepts_bearer_prefix_and_whitespace(monkeypatch):
    monkeypatch.setattr(
        dependencies,
        "get_settings",
        lambda: SimpleNamespace(codegen_actions_callback_token=" Bearer callback-secret "),
    )

    assert dependencies._validate_actions_callback_token(
        "Bearer   callback-secret  "
    )


def test_actions_callback_token_rejects_wrong_secret(monkeypatch):
    monkeypatch.setattr(
        dependencies,
        "get_settings",
        lambda: SimpleNamespace(codegen_actions_callback_token="callback-secret"),
    )

    assert not dependencies._validate_actions_callback_token("Bearer other-secret")


def test_codegen_action_grant_is_scoped_to_one_run(monkeypatch):
    monkeypatch.setattr(jwt_security, "settings", SimpleNamespace(jwt_secret="test-secret"))
    run_id = uuid4()
    token = jwt_security.create_codegen_action_grant_token(
        run_id, uuid4(), uuid4()
    )

    grant = jwt_security.decode_codegen_action_grant_token(token)
    assert grant is not None
    assert grant.run_id == str(run_id)
    assert jwt_security.decode_codegen_action_grant_token(token + "x") is None


async def test_denial_is_logged_with_the_specific_reason_not_just_forbidden(monkeypatch):
    # A bare ForbiddenError with no server-side record of *why* is exactly what
    # made the live incident this covers take DB/settings archaeology to
    # diagnose -- assert the reason is actually logged, not just that it 403s.
    monkeypatch.setattr(
        dependencies,
        "get_settings",
        lambda: SimpleNamespace(codegen_actions_callback_token=""),
    )
    run_id = uuid4()
    with structlog.testing.capture_logs() as logs:
        with pytest.raises(ForbiddenError):
            await dependencies.require_run_grant_or_actions_token(
                run=run_id, authorization="Bearer not-a-real-token", db=AsyncMock()
            )
    [event] = [log for log in logs if log["event"] == "codegen_callback_denied"]
    assert event["run_id"] == str(run_id)
    assert event["reason"] == "static_token_mismatch_and_no_decodable_grant"
