from types import SimpleNamespace
from typing import cast

import pytest
from aws_lambda_typing.context import Context
from aws_lambda_typing.events import APIGatewayProxyEventV1
from punq import Container

from iisi_app_core import (
    ApiGatewayEventHandler,
    MissingRequestScopeError,
    Principal,
    RequestScope,
    build_lambda_handler,
    correlation_id,
    get_app_context,
    principal,
    set_principal,
)


def _context() -> Context:
    return cast(Context, SimpleNamespace(function_name="test"))


def test_request_scope_exposes_state_and_resets() -> None:
    container = Container()

    with RequestScope(correlation_id="cid-1", principal=Principal.system(), container=container):
        assert get_app_context() is container
        assert correlation_id() == "cid-1"
        assert principal().name == "system"

    with pytest.raises(MissingRequestScopeError):
        get_app_context()
    assert principal().name == "guest"


def test_request_scope_resets_after_exception() -> None:
    container = Container()

    with pytest.raises(ValueError):
        with RequestScope(correlation_id="cid-2", principal=Principal.guest(), container=container):
            set_principal(Principal.system())
            raise ValueError("boom")

    assert principal().name == "guest"


def test_build_lambda_handler_sets_container_scope_for_resolved_handler() -> None:
    container = Container()
    seen: dict[str, object] = {}

    class RecordingHandler:
        def handle(self, event):  # noqa: ANN001, ANN202
            del event
            seen["container"] = get_app_context()
            seen["principal"] = principal().name
            return {
                "statusCode": 200,
                "headers": {},
                "multiValueHeaders": {},
                "body": "",
                "isBase64Encoded": False,
            }

    container.register(ApiGatewayEventHandler, instance=cast(ApiGatewayEventHandler, RecordingHandler()))
    handler = build_lambda_handler(lambda event, context: container)

    response = handler(
        cast(APIGatewayProxyEventV1, {"httpMethod": "GET", "resource": "/items", "headers": {}}),
        _context(),
    )

    assert response["statusCode"] == 200
    assert seen["container"] is container
    assert seen["principal"] == "guest"
