import psycopg
from fastapi.security import HTTPAuthorizationCredentials
from jose import JWTError, jwt
from src.__types.index import Tenant
from src.infrastructure.repositories.tenant_repository import TenantRepository
from src.routers.auth_helpers import (
    get_key,
    get_kid,
)
from src.settings import Settings
from src.tracer import tracer

settings = Settings()


@tracer.capture_method
def get_m2m_tenant(
    credential: HTTPAuthorizationCredentials,
) -> Tenant:
    """M2Mアクセストークンを検証し、テナント情報を返す

    raise:
        ValueError: 設定不備
        JWTError: トークンの検証に失敗した場合
    """
    issuer = settings.management_m2m_issuer
    if not issuer:
        raise ValueError("Management M2M issuer is not configured.")

    # アクセストークンの検証
    token = credential.credentials
    jwks_url = issuer + "/.well-known/jwks.json"
    decoded_token = jwt.decode(
        token=token,
        key=get_key(get_kid(token), jwks_url),
        algorithms=["RS256"],
        options={
            "verify_signature": True,
            "verify_aud": False,  # TODO: aud検証を有効化する
            "verify_iat": True,
            "verify_exp": True,
            "verify_nbf": True,
            "verify_iss": True,
            "verify_sub": True,
            "verify_jti": True,
            "verify_at_hash": True,
            "require_aud": False,
            "require_iat": False,
            "require_exp": False,
            "require_nbf": False,
            "require_iss": False,
            "require_sub": False,
            "require_jti": False,
            "require_at_hash": False,
            "leeway": 0,
        },
        issuer=issuer,
    )

    if decoded_token.get("token_use") != "access":
        raise JWTError("Invalid token_use: expected 'access'.")

    tenant_id = decoded_token.get("tenant_id")
    if tenant_id is None:
        raise JWTError("Missing required claim: 'tenant_id'.")
    tracer.put_annotation("TenantId", str(tenant_id))

    # Tenant 解決
    with psycopg.connect(settings.postgres_url) as connection:
        repository = TenantRepository(connection=connection)
        return repository.get(tenant_id)
