import psycopg
from aws_lambda_powertools.utilities.typing import LambdaContext
from src.__types.index import Tenant
from src.infrastructure.repositories.tenant_repository import TenantRepository
from src.logger import logger
from src.settings import Settings

settings = Settings()


def handler(event: dict, _: LambdaContext) -> dict:
    with psycopg.connect(settings.postgres_url) as connection:
        tenant_repository = TenantRepository(
            connection=connection,
        )
        application_client_id = event.get("callerContext", {}).get("clientId")
        if not application_client_id:
            raise KeyError("application_client_id is required in the event request.")

        tenant = tenant_repository.get_by_m2m_application_client_id(application_client_id)
        metadata = event.get("request", {}).get("clientMetadata", {})
        _verify_metadata(tenant, metadata)

        # アクセス トークンの生成時にテナントIDをクレームとして追加
        event["response"] = {
            "claimsAndScopeOverrideDetails": {
                "accessTokenGeneration": {
                    "claimsToAddOrOverride": {
                        "tenant_id": str(tenant.id),
                    },
                },
            },
        }
    return event


def _verify_metadata(tenant: Tenant, metadata: dict) -> None:
    logger.debug(
        "verify_client_metadata",
        received_metadata=metadata,
        allowed_metadata_patterns=tenant.allowed_m2m_metadata,
    )
    if not metadata:
        logger.error(
            "client_metadata_required",
            tenant_legal_name=tenant.legal_name,
        )
        raise ValueError("Client metadata is required.")

    for allowed_metadata in tenant.allowed_m2m_metadata:
        # allowed_metadataの全てのキーと値がmetadataに含まれているかを確認する
        if allowed_metadata.items() <= metadata.items():
            return

    logger.error(
        "client_metadata_verification_failed",
        received_metadata=metadata,
        allowed_metadata_patterns=tenant.allowed_m2m_metadata,
        tenant_legal_name=tenant.legal_name,
    )
    raise ValueError("Invalid client metadata provided.")
