from datetime import datetime
from typing import Annotated, Any

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

from zbt.api.responses import success_response
from zbt.core.errors import AppError
from zbt.domains.attribution.service import AttributionService
from zbt.domains.catalog.service import ProductCatalogService
from zbt.domains.enrollment.service import EnrollmentService
from zbt.domains.identity.models import AdminUser
from zbt.domains.identity.service import AdminAuthService

admin_business_bearer = HTTPBearer(auto_error=False)


class RoleUpdateRequest(BaseModel):
    permissions: list[str] = Field(default_factory=list, max_length=50)
    data_scope: str = Field(min_length=2, max_length=32)


class AdminUserCreateRequest(BaseModel):
    username: str = Field(min_length=3, max_length=32)
    password: str = Field(min_length=8, max_length=128)
    display_name: str = Field(min_length=1, max_length=64)
    role_code: str = Field(min_length=2, max_length=64)


class AdminUserUpdateRequest(BaseModel):
    display_name: str = Field(min_length=1, max_length=64)
    status: str = Field(min_length=2, max_length=32)
    role_code: str = Field(min_length=2, max_length=64)


class PasswordResetRequest(BaseModel):
    new_password: str = Field(min_length=8, max_length=128)


class UserStatusRequest(BaseModel):
    status: str = Field(min_length=2, max_length=32)


class ProductStatusRequest(BaseModel):
    status: str = Field(pattern="^(ACTIVE|INACTIVE)$")


class ProductUpdateRequest(BaseModel):
    name: str = Field(min_length=1, max_length=128)
    category: str = Field(pattern="^(MEDICAL|ACCIDENT)$")
    summary: str = Field(min_length=1, max_length=500)


class ProductVersionCreateRequest(BaseModel):
    version_no: str = Field(min_length=1, max_length=32)
    effective_from: datetime
    source_version_id: str | None = Field(default=None, max_length=26)


class ProductPlanRequest(BaseModel):
    id: str | None = Field(default=None, max_length=26)
    code: str = Field(min_length=1, max_length=32)
    name: str = Field(min_length=1, max_length=128)
    summary: str = Field(default="", max_length=500)
    status: str = Field(pattern="^(ACTIVE|INACTIVE)$")
    premium_cents: int = Field(ge=0, le=100_000_000)
    coverage_amount_cents: int = Field(ge=0, le=100_000_000_000)
    min_age: int = Field(ge=0, le=120)
    max_age: int = Field(ge=0, le=120)


class ProductCreateRequest(BaseModel):
    product_code: str = Field(min_length=3, max_length=32)
    name: str = Field(min_length=1, max_length=128)
    category: str = Field(pattern="^(MEDICAL|ACCIDENT)$")
    summary: str = Field(min_length=1, max_length=500)
    version_no: str = Field(default="1.0.0", min_length=1, max_length=32)
    effective_from: datetime
    rule_version: str = Field(default="eligibility-v1", min_length=1, max_length=32)
    rate_version: str = Field(default="rate-v1", min_length=1, max_length=32)
    terms_summary: str = Field(default="", max_length=5000)
    plans: list[ProductPlanRequest] = Field(min_length=1, max_length=12)


class ProductVersionUpdateRequest(BaseModel):
    effective_from: datetime
    effective_to: datetime | None = None
    rule_version: str = Field(min_length=1, max_length=32)
    rate_version: str = Field(min_length=1, max_length=32)
    terms_summary: str = Field(default="", max_length=5000)
    plans: list[ProductPlanRequest] = Field(min_length=1, max_length=12)


def create_admin_business_router(
    service: EnrollmentService,
    auth_service: AdminAuthService,
    catalog_service: ProductCatalogService,
    attribution_service: AttributionService,
) -> APIRouter:
    router = APIRouter(tags=["admin-business"])

    def current_admin(
        credentials: Annotated[
            HTTPAuthorizationCredentials | None,
            Depends(admin_business_bearer),
        ],
    ) -> AdminUser:
        if credentials is None:
            raise AppError("AUTH_REQUIRED", "请先登录后台", 401)
        return auth_service.authenticate_access(credentials.credentials)

    def require_read(user: AdminUser, permission: str) -> None:
        if "*" not in user.permissions and permission not in user.permissions:
            raise AppError("PERMISSION_DENIED", "当前角色无权访问该数据", 403)

    def scoped_orders(user: AdminUser) -> dict[str, Any]:
        result = service.list_orders()
        if user.data_scope == "SELF":
            allowed = attribution_service.order_ids(user.id)
            items = [item for item in result["items"] if item["order_id"] in allowed]
            result = {"items": items, "total": len(items)}
        if user.data_scope != "ALL":
            result = {
                "items": [_mask_order(item) for item in result["items"]],
                "total": result["total"],
            }
        return result

    def scoped_policies(user: AdminUser) -> dict[str, Any]:
        result = service.list_all_policies()
        if user.data_scope == "SELF":
            allowed = attribution_service.order_ids(user.id)
            items = [item for item in result["items"] if item["order_id"] in allowed]
            result = {"items": items, "total": len(items)}
        if user.data_scope != "ALL":
            result = {
                "items": [_mask_policy(item) for item in result["items"]],
                "total": result["total"],
            }
        return result

    @router.get("/admin/dashboard")
    def dashboard(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "dashboard:read")
        orders = scoped_orders(user)
        policies = scoped_policies(user)
        active_policies = [item for item in policies["items"] if item["status"] == "ACTIVE"]
        return success_response(
            request,
            {
                "order_count": orders["total"],
                "policy_count": len(active_policies),
                "premium_cents": sum(int(item["premium_cents"]) for item in active_policies),
            },
        )

    @router.get("/admin/orders")
    def orders(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "order:read")
        return success_response(request, scoped_orders(user))

    @router.get("/admin/orders/{order_id}")
    def order_detail(
        order_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "order:read")
        item = next(
            (order for order in scoped_orders(user)["items"] if order["order_id"] == order_id),
            None,
        )
        if item is None:
            raise AppError("ORDER_NOT_FOUND", "未找到订单或无权查看", 404)
        return success_response(request, item)

    @router.get("/admin/policies")
    def policies(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "policy:read")
        return success_response(request, scoped_policies(user))

    @router.get("/admin/policies/{policy_id}")
    def policy_detail(
        policy_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "policy:read")
        item = next(
            (
                policy
                for policy in scoped_policies(user)["items"]
                if policy["policy_id"] == policy_id
            ),
            None,
        )
        if item is None:
            raise AppError("POLICY_NOT_FOUND", "未找到保单或无权查看", 404)
        return success_response(request, item)

    @router.get("/admin/products")
    def products(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:read")
        return success_response(request, catalog_service.list_managed())

    @router.post("/admin/products", status_code=201)
    def create_product(
        payload: ProductCreateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.create_product(
                product_code=payload.product_code,
                name=payload.name,
                category=payload.category,
                summary=payload.summary,
                version_no=payload.version_no,
                effective_from=payload.effective_from,
                rule_version=payload.rule_version,
                rate_version=payload.rate_version,
                terms_summary=payload.terms_summary,
                plans=[plan.model_dump() for plan in payload.plans],
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.put("/admin/products/{product_id}/status")
    def update_product_status(
        product_id: str,
        payload: ProductStatusRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.update_product_status(
                product_id,
                payload.status,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.put("/admin/products/{product_id}")
    def update_product(
        product_id: str,
        payload: ProductUpdateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.update_product(
                product_id,
                name=payload.name,
                category=payload.category,
                summary=payload.summary,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.post("/admin/products/{product_id}/versions", status_code=201)
    def create_product_version(
        product_id: str,
        payload: ProductVersionCreateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.create_draft_version(
                product_id,
                version_no=payload.version_no,
                effective_from=payload.effective_from,
                source_version_id=payload.source_version_id,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.put("/admin/products/{product_id}/versions/{version_id}")
    def update_product_version(
        product_id: str,
        version_id: str,
        payload: ProductVersionUpdateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.update_draft_version(
                product_id,
                version_id,
                effective_from=payload.effective_from,
                effective_to=payload.effective_to,
                rule_version=payload.rule_version,
                rate_version=payload.rate_version,
                terms_summary=payload.terms_summary,
                plans=[plan.model_dump() for plan in payload.plans],
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.post("/admin/products/{product_id}/versions/{version_id}/publish")
    def publish_product_version(
        product_id: str,
        version_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.publish_version(
                product_id,
                version_id,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.post("/admin/products/{product_id}/versions/{version_id}/retire")
    def retire_product_version(
        product_id: str,
        version_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.retire_version(
                product_id,
                version_id,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.delete("/admin/products/{product_id}/versions/{version_id}")
    def delete_product_version(
        product_id: str,
        version_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:write")
        return success_response(
            request,
            catalog_service.delete_draft_version(
                product_id,
                version_id,
                actor_id=user.id,
                actor_name=user.display_name,
            ),
        )

    @router.get("/admin/products/{product_id}/logs")
    def product_change_logs(
        product_id: str,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "product:read")
        return success_response(
            request,
            catalog_service.list_change_logs(product_id),
        )

    @router.get("/admin/attribution/overview")
    def attribution_overview(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "attribution:read")
        owner_id = user.id if user.data_scope == "SELF" else None
        return success_response(
            request,
            attribution_service.performance(owner_id),
        )

    @router.get("/admin/attribution/codes")
    def attribution_codes(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "attribution:read")
        owner_id = user.id if user.data_scope == "SELF" else None
        return success_response(
            request,
            attribution_service.list_codes(owner_id),
        )

    @router.get("/admin/roles")
    def roles(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "role:read")
        return success_response(request, auth_service.list_roles())

    @router.put("/admin/roles/{role_code}")
    def update_role(
        role_code: str,
        payload: RoleUpdateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "role:write")
        return success_response(
            request,
            auth_service.update_role(
                role_code,
                permissions=payload.permissions,
                data_scope=payload.data_scope,
            ),
        )

    @router.get("/admin/users")
    def managed_users(
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "user:read")
        return success_response(request, auth_service.list_managed_users())

    @router.post("/admin/users/admins", status_code=201)
    def create_admin_user(
        payload: AdminUserCreateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "user:write")
        return success_response(
            request,
            auth_service.create_admin_user(
                username=payload.username,
                password=payload.password,
                display_name=payload.display_name,
                role_code=payload.role_code,
            ),
        )

    @router.put("/admin/users/admins/{user_id}")
    def update_admin_user(
        user_id: str,
        payload: AdminUserUpdateRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "user:write")
        return success_response(
            request,
            auth_service.update_admin_user(
                user,
                user_id,
                display_name=payload.display_name,
                status=payload.status,
                role_code=payload.role_code,
            ),
        )

    @router.post("/admin/users/admins/{user_id}/password")
    def reset_admin_password(
        user_id: str,
        payload: PasswordResetRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "user:write")
        return success_response(
            request,
            auth_service.reset_admin_password(
                user_id,
                new_password=payload.new_password,
            ),
        )

    @router.put("/admin/users/customers/{user_id}/status")
    def update_customer_status(
        user_id: str,
        payload: UserStatusRequest,
        request: Request,
        user: Annotated[AdminUser, Depends(current_admin)],
    ) -> dict[str, Any]:
        require_read(user, "user:write")
        return success_response(
            request,
            auth_service.update_customer_status(
                user_id,
                status=payload.status,
            ),
        )

    return router


def _mask_secret(value: str | None) -> str:
    if not value:
        return ""
    if len(value) == 11:
        return f"{value[:3]}****{value[-4:]}"
    if len(value) >= 10:
        return f"{value[:6]}********{value[-4:]}"
    return value


def _mask_person(person: dict[str, Any]) -> dict[str, Any]:
    masked = dict(person)
    if "id_no" in masked:
        masked["id_no"] = _mask_secret(str(masked["id_no"]))
    return masked


def _mask_order(item: dict[str, Any]) -> dict[str, Any]:
    masked = dict(item)
    masked["applicant"] = _mask_person(dict(item.get("applicant", {})))
    masked["insured"] = _mask_person(dict(item.get("insured", {})))
    contact = dict(item.get("contact", {}))
    if "mobile" in contact:
        contact["mobile"] = _mask_secret(str(contact["mobile"]))
    masked["contact"] = contact
    return masked


def _mask_policy(item: dict[str, Any]) -> dict[str, Any]:
    masked = dict(item)
    masked["applicant"] = _mask_person(dict(item.get("applicant", {})))
    masked["insured"] = _mask_person(dict(item.get("insured", {})))
    return masked
