from collections.abc import Generator
from unittest.mock import MagicMock
from uuid import UUID

import pytest
import src.usecases.user_command_usecase as user_command_usecase_module
from fastapi.testclient import TestClient
from src.__types.index import Tenant
from src.const import MANAGEMENT_TENANT_NAME_HEADER
from src.infrastructure.clients.cognito_idp_client import CognitoIdpClient
from src.management_api import app
from src.routers.management.authorizer import get_tenant, get_user_id


@pytest.fixture(scope="session")
def registered_identifiers() -> dict[str, str]:
    return {
        "tenant_alpha_id": "00000001-0000-0000-0000-000000000000",
        "tenant_alpha_name": "alpha",
        "tenant_alpha_m2m_application_client_id": "application_client#alpha",
        "tenant_alpha_user_application_client_id": "user_application_client#alpha",
        "tenant_alpha_whi_customer_id_1": "whi#alpha_1",
        "tenant_alpha_whi_customer_id_2": "whi#alpha_2",
        "tenant_alpha_cydas_customer_id": "cydas#alpha",
        "tenant_alpha_allowed_caller_service": "ctm",
        "tenant_alpha_allowed_tenant_name": "client_tenant_alpha_alpha_1",
        "tenant_beta_id": "00000002-0000-0000-0000-000000000000",
        "tenant_beta_name": "beta",
        "user_alpha_admin_id": "00000001-0000-0000-0000-000000000000",
        "user_alpha_member_id": "00000001-0000-0000-0000-000000000001",
        "user_alpha_member2_id": "00000001-0000-0000-0000-000000000002",
        "user_beta_member_id": "00000002-0000-0000-0000-000000000000",
    }


@pytest.fixture(scope="session")
def header_names() -> dict[str, str]:
    return {
        "tenant_name": MANAGEMENT_TENANT_NAME_HEADER,
    }


@pytest.fixture
def mock_cognito_client(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
    mock_client = MagicMock(spec_set=CognitoIdpClient)

    def mock_cognito_client_factory(**_: str) -> MagicMock:
        return mock_client

    monkeypatch.setattr(user_command_usecase_module.settings, "management_user_pool_id", "dummy_user_pool")
    monkeypatch.setattr(
        user_command_usecase_module,
        "CognitoIdpClient",
        mock_cognito_client_factory,
    )

    return mock_client


@pytest.fixture(scope="session")
def tenant_alpha(registered_identifiers: dict[str, str]) -> Tenant:
    return Tenant(
        id=UUID(registered_identifiers["tenant_alpha_id"]),
        m2m_application_client_id=registered_identifiers["tenant_alpha_m2m_application_client_id"],
        legal_name="アルファ株式会社",
        name=registered_identifiers["tenant_alpha_name"],
        whi_customer_id=[
            registered_identifiers["tenant_alpha_whi_customer_id_1"],
            registered_identifiers["tenant_alpha_whi_customer_id_2"],
        ],
        cydas_customer_id=[registered_identifiers["tenant_alpha_cydas_customer_id"]],
        allowed_m2m_metadata=[
            {
                "callerService": registered_identifiers["tenant_alpha_allowed_caller_service"],
                "tenantName": registered_identifiers["tenant_alpha_allowed_tenant_name"],
            },
        ],
    )


@pytest.fixture
def test_client(tenant_alpha: Tenant) -> Generator[TestClient, None, None]:
    def get_authenticated_tenant() -> Tenant:
        return tenant_alpha

    app.dependency_overrides[get_tenant] = get_authenticated_tenant
    try:
        with TestClient(app) as test_client:
            yield test_client
    finally:
        app.dependency_overrides.pop(get_tenant, None)


@pytest.fixture
def test_client_as_member(
    tenant_alpha: Tenant,
    registered_identifiers: dict[str, str],
) -> Generator[TestClient, None, None]:
    """user_alpha_member として認証されたテストクライアント。"""
    user_id = UUID(registered_identifiers["user_alpha_member_id"])

    def get_authenticated_tenant() -> Tenant:
        return tenant_alpha

    def get_authenticated_user_id() -> UUID:
        return user_id

    app.dependency_overrides[get_tenant] = get_authenticated_tenant
    app.dependency_overrides[get_user_id] = get_authenticated_user_id
    try:
        with TestClient(app) as test_client:
            yield test_client
    finally:
        app.dependency_overrides.pop(get_tenant, None)
        app.dependency_overrides.pop(get_user_id, None)
