from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, Path, status
from fastapi.responses import PlainTextResponse
from psycopg import Connection
from pydantic import BaseModel, Field
from src.__types.errors import NonUniqueCustomerIdError, ResourceDuplicatedError
from src.__types.index import Client, Distribution
from src.logger import logger
from src.routers.client.authorizer import get_client
from src.routers.client.connection import get_connection
from src.usecases.client_tenant_usecase import ClientTenantListItem, ClientTenantUseCase

router = APIRouter(
    prefix="/client-tenants",
    tags=[
        "テナント",
    ],  # NOTE: 本来は"クライアントテナント"が適切だが、クライアント開発者にとってはわかりづらいため"テナント"と呼び替えている。
)


class GetResponse(BaseModel):
    tenants: list[ClientTenantListItem] = Field(..., description="登録されているテナントの一覧")


class PostRequest(BaseModel):
    distribution: Distribution = Field(
        ...,
        description="""
        WHIもしくはCYDASどちらのSFDCか。
""",
        examples=["whi_sfdc", "cydas_sfdc"],
    )
    customer_id: str = Field(
        ...,
        min_length=1,
        description="""
        SFDCの取引先ID。
""",
    )
    base_url: str | None = Field(
        None,
        description="""
        テナントのベースURL。
        ※ AIユニット管理画面でそのテナントが何のかをユーザーが識別するために利用予定です。

        例:
        - https://whi-ctm.company.works-hi.com (テナント別URL)
        - https://peoplefeature14-login.cydas.com/ppfeature14_whi_ai_test (テナント別URLパス)
        - https://hci.app.works-hi.co.jp (共通ドメイン)
        """,
    )


@router.get(
    "",
    summary="登録されているテナント一覧の取得",
    status_code=status.HTTP_200_OK,
    responses={
        status.HTTP_200_OK: {
            "description": "テナント一覧の取得に成功",
        },
        status.HTTP_401_UNAUTHORIZED: {
            "description": "認証失敗",
        },
        status.HTTP_429_TOO_MANY_REQUESTS: {
            "description": "レートリミットエラー ※ リトライを推奨します。",
        },
        status.HTTP_500_INTERNAL_SERVER_ERROR: {
            "description": "内部エラー",
        },
    },
)
def get(
    client: Annotated[Client, Depends(get_client)],
    connection: Annotated[Connection, Depends(get_connection)],
) -> GetResponse:
    usecase = ClientTenantUseCase.create(connection=connection)
    return GetResponse(
        tenants=[
            ClientTenantListItem(name=client_tenant.name, status=client_tenant.status)
            for client_tenant in usecase.get(client=client)
        ],
    )


@router.post(
    "/{name}",
    summary="テナントの登録",
    status_code=status.HTTP_200_OK,
    response_class=PlainTextResponse,
    responses={
        status.HTTP_200_OK: {
            "description": "テナントの登録に成功",
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "不正なリクエスト",
        },
        status.HTTP_401_UNAUTHORIZED: {
            "description": "認証失敗",
        },
        status.HTTP_403_FORBIDDEN: {
            "description": "権限の不足",
        },
        status.HTTP_409_CONFLICT: {
            "description": "リクエストの内容が現在のサーバーの状態と矛盾している場合(例: すでに同名のテナントが存在する)",
        },
        status.HTTP_422_UNPROCESSABLE_CONTENT: {
            "description": "リクエストボディのバリデーションエラー",
        },
        status.HTTP_429_TOO_MANY_REQUESTS: {
            "description": "レートリミットエラー ※ リトライを推奨します。",
        },
        status.HTTP_500_INTERNAL_SERVER_ERROR: {
            "description": "内部エラー",
        },
    },
)
def post(
    client: Annotated[Client, Depends(get_client)],
    request: PostRequest,
    connection: Annotated[Connection, Depends(get_connection)],
    name: Annotated[
        str,
        Path(
            ...,
            min_length=1,
            description="""
    作成するテナント名。クォータ確認API等で`X-Tenant-Name`ヘッダーに指定する値になります。クライアント内で一意であればどのような値でも構いません。
    ※ 日本語の指定は禁止
    例:
    - whi
    - whi-test
    - whi_12345
    - whi-develop
    - whi-staging
    - whi-production""",
        ),
    ],
) -> PlainTextResponse:
    logger.info(
        "register_client_tenant_request",
        client_id=client.id,
        tenant_name=name,
        distribution=request.distribution,
        customer_id=request.customer_id,
    )
    usecase = ClientTenantUseCase.create(connection=connection)
    try:
        linked_tenant = usecase.add(
            client=client,
            customer_id=request.customer_id,
            distribution=request.distribution,
            name=name,
            base_url=request.base_url,
        )
    except NonUniqueCustomerIdError as e:
        logger.warning(
            "non_unique_customer_id",
            client_id=client.id,
            tenant_name=name,
            distribution=request.distribution,
            customer_id=request.customer_id,
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Customer id is not unique in database, please contact administrator.",
        ) from e
    except ResourceDuplicatedError as e:
        logger.warning(
            "duplicated_client_tenant",
            client_id=client.id,
            tenant_name=name,
            distribution=request.distribution,
            customer_id=request.customer_id,
        )
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="A tenant with the same name is already registered.",
        ) from e

    return PlainTextResponse(
        status_code=status.HTTP_200_OK,
        content=f"Tenant '{name}' is registered and linked to Customer '{linked_tenant.legal_name}' successfully."
        if linked_tenant
        else f"Tenant '{name}' is registered, but it is not linked to any Customer yet.",
    )
