"""H5 投保 HTTP 接口。

接口负责校验请求结构和当前登录用户，再把确定性业务交给 EnrollmentService。
模型不会直接调用这些交易接口，必须由用户在页面上确认后提交。
"""

from typing import Annotated, Any

from fastapi import APIRouter, Depends, Header, Request, Response, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import BaseModel, Field

from zbt.api.responses import success_response
from zbt.core.config import Settings
from zbt.core.errors import AppError
from zbt.domains.enrollment.service import EnrollmentService
from zbt.domains.identity.models import H5User
from zbt.domains.identity.service import H5AuthService

enrollment_bearer_scheme = HTTPBearer(auto_error=False)


class InsuredInput(BaseModel):
    """报价时需要的被保险人基本条件。"""

    age: int = Field(ge=0, le=120)
    region_code: str = Field(min_length=6, max_length=12)
    occupation_code: str = Field(min_length=1, max_length=32)


class CreateQuoteRequest(BaseModel):
    """创建报价的请求体。"""

    product_id: str = Field(min_length=26, max_length=26)
    plan_id: str = Field(min_length=26, max_length=26)
    insured: InsuredInput
    relationship: str = Field(pattern="^(SELF|PARENT|SPOUSE|CHILD)$")


class PersonInput(BaseModel):
    """投保人或被保险人的实名信息。"""

    name: str = Field(min_length=1, max_length=64)
    id_no: str = Field(min_length=6, max_length=32)


class ContactInput(BaseModel):
    """用于接收投保通知的联系方式。"""

    mobile: str = Field(min_length=11, max_length=11)


class CreateDraftRequest(BaseModel):
    """保存投保草稿的请求体。"""

    quote_id: str = Field(min_length=26, max_length=26)
    applicant: PersonInput
    insured: PersonInput
    contact: ContactInput


class CreateOrderRequest(BaseModel):
    """用户确认后创建订单的请求体。"""

    draft_id: str = Field(min_length=26, max_length=26)
    confirmation_token: str = Field(min_length=32, max_length=128)


class MockPaymentCallbackRequest(BaseModel):
    """本地模拟支付协议的数据结构，不代表真实支付渠道。"""

    callback_no: str = Field(min_length=1, max_length=64)
    provider_transaction_no: str = Field(min_length=1, max_length=64)
    payment_no: str = Field(min_length=1, max_length=40)
    status: str = Field(pattern="^(SUCCEEDED|FAILED)$")
    amount_cents: int = Field(gt=0)
    occurred_at: str = Field(min_length=10, max_length=64)


def create_enrollment_router(
    service: EnrollmentService,
    h5_auth_service: H5AuthService,
    settings: Settings,
) -> APIRouter:
    """创建投保路由，并绑定已装配好的业务服务与认证服务。"""

    router = APIRouter(tags=["enrollment"])

    def current_h5_user(
        credentials: Annotated[
            HTTPAuthorizationCredentials | None,
            Depends(enrollment_bearer_scheme),
        ],
    ) -> H5User:
        """FastAPI 依赖：验证 Token 并返回当前 H5 用户。"""

        if credentials is None:
            raise AppError("AUTH_REQUIRED", "请先登录", 401)
        return h5_auth_service.authenticate_access(credentials.credentials)

    @router.post("/h5/quotes", status_code=status.HTTP_201_CREATED)
    def create_quote(
        payload: CreateQuoteRequest,
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """创建确定性报价。"""

        return success_response(
            request,
            service.create_quote(
                user,
                product_id=payload.product_id,
                plan_id=payload.plan_id,
                age=payload.insured.age,
                region_code=payload.insured.region_code,
                occupation_code=payload.insured.occupation_code,
                relationship=payload.relationship,
            ),
        )

    @router.post("/h5/enrollment-drafts", status_code=status.HTTP_201_CREATED)
    def create_draft(
        payload: CreateDraftRequest,
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """保存投保资料草稿。"""

        return success_response(
            request,
            service.create_draft(
                user,
                quote_id=payload.quote_id,
                applicant=payload.applicant.model_dump(),
                insured=payload.insured.model_dump(),
                contact=payload.contact.model_dump(),
            ),
        )

    @router.post(
        "/h5/enrollment-drafts/{draft_id}/confirmation",
        status_code=status.HTTP_201_CREATED,
    )
    def confirm_draft(
        draft_id: str,
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """确认草稿并返回短时有效的确认令牌。"""

        return success_response(request, service.confirm_draft(user, draft_id))

    @router.post("/h5/orders", status_code=status.HTTP_201_CREATED)
    def create_order(
        payload: CreateOrderRequest,
        request: Request,
        response: Response,
        user: Annotated[H5User, Depends(current_h5_user)],
        idempotency_key: Annotated[
            str,
            Header(alias="Idempotency-Key", min_length=1, max_length=64),
        ],
    ) -> dict[str, Any]:
        """使用确认令牌创建订单；幂等键由请求头提供。"""

        data, created = service.create_order(
            user,
            draft_id=payload.draft_id,
            confirmation_token=payload.confirmation_token,
            idempotency_key=idempotency_key,
        )
        response.status_code = status.HTTP_201_CREATED if created else status.HTTP_200_OK
        return success_response(request, data)

    @router.post(
        "/h5/orders/{order_id}/payments",
        status_code=status.HTTP_201_CREATED,
    )
    def create_payment(
        order_id: str,
        request: Request,
        response: Response,
        user: Annotated[H5User, Depends(current_h5_user)],
        idempotency_key: Annotated[
            str,
            Header(alias="Idempotency-Key", min_length=1, max_length=64),
        ],
    ) -> dict[str, Any]:
        """为待支付订单创建本地模拟支付流水。"""

        data, created = service.create_payment(
            user,
            order_id=order_id,
            idempotency_key=idempotency_key,
        )
        response.status_code = status.HTTP_201_CREATED if created else status.HTTP_200_OK
        return success_response(request, data)

    @router.post("/dev/mock-payments/{payment_id}/complete")
    def complete_mock_payment(
        payment_id: str,
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """本地开发入口：完成模拟支付并推进出单流程。"""

        if not settings.dev_tools_enabled or settings.app_env == "production":
            raise AppError("DEV_TOOL_DISABLED", "本地模拟支付未启用", 404)
        return success_response(
            request,
            service.complete_mock_payment(user, payment_id=payment_id),
        )

    @router.post("/callbacks/mock-payment")
    def mock_payment_callback(
        payload: MockPaymentCallbackRequest,
        request: Request,
        signature: Annotated[
            str,
            Header(alias="X-Mock-Pay-Signature", min_length=1, max_length=128),
        ],
    ) -> dict[str, Any]:
        """本地模拟协议入口：校验签名后处理支付结果。"""

        return success_response(
            request,
            service.handle_mock_callback(payload.model_dump(), signature),
        )

    @router.get("/h5/policies")
    def list_policies(
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """查询当前用户自己的电子保单。"""

        return success_response(request, service.list_policies(user))

    @router.get("/h5/orders")
    def list_orders(
        request: Request,
        user: Annotated[H5User, Depends(current_h5_user)],
    ) -> dict[str, Any]:
        """查询当前用户自己的投保订单。"""

        return success_response(request, service.list_orders(user.id))

    return router
