from typing import Any

from fastapi import FastAPI, HTTPException, Request, Response, status
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from mangum import Mangum
from mangum.types import LambdaContext, LambdaEvent
from src.__types.error_responses import VALIDATION_FAILED_DETAIL, ErrorResponse
from src.__types.errors import ClientError
from src.logger import logger
from src.routers.contract import contract_events_router
from src.routers.contract.description import ROOT_DESCRIPTION, TAGS
from src.routers.http_errors import request_validation_error_to_invalid_params
from src.settings import Settings
from src.tracer import tracer

settings = Settings()


app = FastAPI(
    title="AI Unit コントラクト API",
    summary="API for AI-Unit contract management",
    description=ROOT_DESCRIPTION,
    version="1.0.0",
    docs_url=None,  # セキュリティのため、利用しないドキュメントは非表示
    # RedocのAPIドキュメントでは、openapi_tagsで指定した順序でエンドポイントが表示される
    openapi_tags=TAGS,
    # 共通のレスポンス定義、個別のエンドポイントで上書き可能
    responses={
        status.HTTP_200_OK: {
            "description": "リクエスト成功",
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "不正なリクエスト",
            "model": ErrorResponse,
        },
        status.HTTP_401_UNAUTHORIZED: {
            "description": "認証失敗",
            "model": ErrorResponse,
        },
        status.HTTP_422_UNPROCESSABLE_CONTENT: {
            "description": "バリデーションエラー",
            "model": ErrorResponse,
        },
        status.HTTP_500_INTERNAL_SERVER_ERROR: {
            "description": "サーバーエラー",
            "model": ErrorResponse,
        },
    },
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.exception_handler(RequestValidationError)
async def request_validation_exception_handler(
    _: Request,
    exc: RequestValidationError,
) -> JSONResponse:
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
        content=ErrorResponse(
            detail=VALIDATION_FAILED_DETAIL,
            invalid_parameters=request_validation_error_to_invalid_params(exc),
        ).model_dump(),
    )


@app.exception_handler(ClientError)
async def client_error_exception_handler(
    _: Request,
    exc: ClientError,
) -> JSONResponse:
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=ErrorResponse(detail=exc.message, invalid_parameters=None).model_dump(),
    )


@app.exception_handler(HTTPException)
async def http_exception_handler(
    _: Request,
    exc: HTTPException,
) -> JSONResponse:
    def _is_error_response_payload(detail: object) -> bool:
        """HTTPException の detail が ErrorResponse の構造をしているか"""
        return isinstance(detail, dict) and isinstance(detail.get("detail"), str)

    content = exc.detail if _is_error_response_payload(exc.detail) else {"detail": exc.detail}

    return JSONResponse(
        status_code=exc.status_code,
        content=content,
        headers=exc.headers,
    )


@app.get(
    "/",
    status_code=status.HTTP_200_OK,
    tags=["その他"],
    responses={
        status.HTTP_200_OK: {
            "description": "ヘルスチェック成功",
        },
    },
    summary="ヘルスチェック",
)
async def health_check() -> Response:
    return Response(status_code=status.HTTP_200_OK)


API_BASE_RESOURCE = "/v1"
app.include_router(
    contract_events_router.router,
    prefix=API_BASE_RESOURCE,
)

mangum = Mangum(app)


@tracer.capture_lambda_handler
@logger.inject_lambda_context
def handler(event: LambdaEvent, context: LambdaContext) -> dict[str, Any]:
    return mangum(event, context)
