from __future__ import annotations

from datetime import UTC, datetime, timedelta
from typing import Annotated

from fastapi import APIRouter, Depends, Header, HTTPException, Query, status
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from app.api.deps import (
    CurrentUserContext,
    get_current_user,
    get_db,
    require_platform_admin_user,
)
from app.schemas.commercial import (
    CommercialAccountRead,
    CommercialAnalyticsRead,
    CommercialCostEventCreate,
    CommercialCostEventRead,
    CommercialEntitlementRead,
    CommercialEntitlementUpsert,
    CommercialMutationRead,
    CommercialPlanActivationRead,
    CommercialPlanCreate,
    CommercialPlanRead,
    CommercialPricingScenarioRead,
    CommercialPricingScenarioWrite,
    CommercialSubscriptionCreate,
    CommercialSubscriptionRead,
    CommercialSubscriptionTransition,
    CommercialVersionAction,
    UsageMeterEventCreate,
    UsageMeterEventRead,
)
from app.services.commercial_access_policy import (
    CommercialAccessPolicy,
    CommercialConfigurationError,
    CommercialConflictError,
    CommercialPermissionError,
)
from app.services.commercial_admin import CommercialAdminService
from app.services.commercial_analytics import CommercialAnalyticsService
from app.services.commercial_entitlements import CommercialEntitlementService
from app.services.commercial_metering import CommercialMeteringService
from app.services.commercial_pricing import CommercialPricingService
from app.services.commercial_queries import CommercialQueryService

router = APIRouter(prefix="/commercial")
DbSession = Annotated[Session, Depends(get_db)]
CurrentUser = Annotated[CurrentUserContext, Depends(get_current_user)]
PlatformAdmin = Annotated[CurrentUserContext, Depends(require_platform_admin_user)]
RequestId = Annotated[
    str,
    Header(alias="X-Request-Id", min_length=1, max_length=120),
]


@router.get("/account", response_model=CommercialAccountRead, summary="读取当前租户商业账户")
def get_current_commercial_account(
    db: DbSession,
    current_user: CurrentUser,
    as_of: datetime | None = None,
) -> CommercialAccountRead:
    try:
        return CommercialEntitlementService(db).get_account(current_user, as_of=as_of)
    except Exception as error:
        raise _http_error(error) from error


@router.get(
    "/admin/tenants/{tenant_id}/account",
    response_model=CommercialAccountRead,
    summary="平台管理员读取租户商业账户",
)
def get_tenant_commercial_account(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    as_of: datetime | None = None,
) -> CommercialAccountRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    return CommercialEntitlementService(db).get_account_for_tenant(target, as_of=as_of)


@router.post(
    "/admin/tenants/{tenant_id}/plans",
    response_model=CommercialPlanRead,
    status_code=status.HTTP_201_CREATED,
    summary="创建租户套餐新版本",
)
def create_commercial_plan(
    tenant_id: str,
    payload: CommercialPlanCreate,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialPlanRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).create_plan(
            target,
            payload,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/plans/{plan_id}/activate",
    response_model=CommercialPlanActivationRead,
    summary="激活套餐版本并退役同编码旧版本",
)
def activate_commercial_plan(
    tenant_id: str,
    plan_id: str,
    payload: CommercialVersionAction,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialPlanActivationRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        result = CommercialAdminService(db).activate_plan(
            target,
            plan_id,
            expected_version=payload.expected_version,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        return result
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/subscriptions",
    response_model=CommercialSubscriptionRead,
    status_code=status.HTTP_201_CREATED,
    summary="创建并激活租户订阅快照",
)
def create_commercial_subscription(
    tenant_id: str,
    payload: CommercialSubscriptionCreate,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialSubscriptionRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).create_subscription(
            target,
            payload,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/subscriptions/{subscription_id}/activate",
    response_model=CommercialSubscriptionRead,
    summary="重新激活可恢复的租户订阅",
)
def activate_commercial_subscription(
    tenant_id: str,
    subscription_id: str,
    payload: CommercialVersionAction,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialSubscriptionRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).activate_subscription(
            target,
            subscription_id,
            expected_version=payload.expected_version,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/subscriptions/{subscription_id}/transition",
    response_model=CommercialSubscriptionRead,
    summary="暂停、标记逾期或终止租户订阅",
)
def transition_commercial_subscription(
    tenant_id: str,
    subscription_id: str,
    payload: CommercialSubscriptionTransition,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialSubscriptionRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).transition_subscription(
            target,
            subscription_id,
            payload,
            actor_id=current_user.username,
            request_id=request_id,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.get(
    "/admin/tenants/{tenant_id}/plans",
    response_model=list[CommercialPlanRead],
    summary="查询租户套餐版本历史",
)
def list_commercial_plans(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    plan_status: str | None = None,
    limit: int = Query(default=100, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
) -> list[CommercialPlanRead]:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    return CommercialQueryService(db).list_plans(
        target,
        status=plan_status,
        limit=limit,
        offset=offset,
    )


@router.get(
    "/admin/tenants/{tenant_id}/subscriptions",
    response_model=list[CommercialSubscriptionRead],
    summary="查询租户订阅历史",
)
def list_commercial_subscriptions(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    subscription_status: str | None = None,
    limit: int = Query(default=100, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
) -> list[CommercialSubscriptionRead]:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    return CommercialQueryService(db).list_subscriptions(
        target,
        status=subscription_status,
        limit=limit,
        offset=offset,
    )


@router.get(
    "/admin/tenants/{tenant_id}/entitlements",
    response_model=list[CommercialEntitlementRead],
    summary="查询租户商业权益历史",
)
def list_commercial_entitlements(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    subscription_id: str | None = None,
    billing_period_id: str | None = None,
    entitlement_status: str | None = None,
    limit: int = Query(default=200, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
) -> list[CommercialEntitlementRead]:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    return CommercialQueryService(db).list_entitlements(
        target,
        subscription_id=subscription_id,
        billing_period_id=billing_period_id,
        status=entitlement_status,
        limit=limit,
        offset=offset,
    )


@router.get(
    "/admin/tenants/{tenant_id}/usage-events",
    response_model=list[UsageMeterEventRead],
    summary="查询租户追加式用量事实",
)
def list_commercial_usage_events(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    subscription_id: str | None = None,
    billing_period_id: str | None = None,
    start: datetime | None = None,
    end: datetime | None = None,
    limit: int = Query(default=200, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
) -> list[UsageMeterEventRead]:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        return CommercialQueryService(db).list_usage_events(
            target,
            subscription_id=subscription_id,
            billing_period_id=billing_period_id,
            start=start,
            end=end,
            limit=limit,
            offset=offset,
        )
    except Exception as error:
        raise _http_error(error) from error


@router.get(
    "/admin/tenants/{tenant_id}/cost-events",
    response_model=list[CommercialCostEventRead],
    summary="查询租户追加式内部成本事实",
)
def list_commercial_cost_events(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    subscription_id: str | None = None,
    billing_period_id: str | None = None,
    start: datetime | None = None,
    end: datetime | None = None,
    limit: int = Query(default=200, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
) -> list[CommercialCostEventRead]:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        return CommercialQueryService(db).list_cost_events(
            target,
            subscription_id=subscription_id,
            billing_period_id=billing_period_id,
            start=start,
            end=end,
            limit=limit,
            offset=offset,
        )
    except Exception as error:
        raise _http_error(error) from error


@router.put(
    "/admin/tenants/{tenant_id}/entitlements",
    response_model=CommercialEntitlementRead,
    summary="创建或版本化更新租户商业权益",
)
def upsert_commercial_entitlement(
    tenant_id: str,
    payload: CommercialEntitlementUpsert,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialEntitlementRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).upsert_entitlement(
            target,
            payload,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/entitlements/{entitlement_id}/activate",
    response_model=CommercialEntitlementRead,
    summary="激活租户商业权益",
)
def activate_commercial_entitlement(
    tenant_id: str,
    entitlement_id: str,
    payload: CommercialVersionAction,
    db: DbSession,
    current_user: PlatformAdmin,
    request_id: RequestId,
) -> CommercialEntitlementRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row = CommercialAdminService(db).activate_entitlement(
            target,
            entitlement_id,
            expected_version=payload.expected_version,
            actor_id=current_user.username,
            request_id=request_id,
            reason=payload.reason,
        )
        db.commit()
        db.refresh(row)
        return row
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/usage-events",
    response_model=CommercialMutationRead,
    summary="幂等写入租户用量事件",
)
def record_commercial_usage(
    tenant_id: str,
    payload: UsageMeterEventCreate,
    db: DbSession,
    current_user: PlatformAdmin,
) -> CommercialMutationRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row, created = CommercialMeteringService(db).record_usage(
            target,
            payload,
            actor_type="admin",
            actor_id=current_user.username,
        )
        db.commit()
        return CommercialMutationRead(created=created, usage_event=row)
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/cost-events",
    response_model=CommercialMutationRead,
    summary="幂等写入平台内部成本事件",
)
def record_commercial_cost(
    tenant_id: str,
    payload: CommercialCostEventCreate,
    db: DbSession,
    current_user: PlatformAdmin,
) -> CommercialMutationRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        row, created = CommercialMeteringService(db).record_cost(target, payload)
        db.commit()
        return CommercialMutationRead(created=created, cost_event=row)
    except Exception as error:
        db.rollback()
        raise _http_error(error) from error


@router.get(
    "/admin/tenants/{tenant_id}/analytics",
    response_model=CommercialAnalyticsRead,
    summary="平台商业与客户价值分账分析",
)
def get_commercial_analytics(
    tenant_id: str,
    db: DbSession,
    current_user: PlatformAdmin,
    start: datetime | None = None,
    end: datetime | None = None,
    as_of: datetime | None = None,
) -> CommercialAnalyticsRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    now = datetime.now(UTC)
    normalized_end = end or now
    normalized_start = start or (normalized_end - timedelta(days=90))
    try:
        return CommercialAnalyticsService(db).build(
            target,
            start=normalized_start,
            end=normalized_end,
            as_of=as_of or now,
        )
    except Exception as error:
        raise _http_error(error) from error


@router.post(
    "/admin/tenants/{tenant_id}/pricing-scenarios",
    response_model=CommercialPricingScenarioRead,
    summary="按真实成本与确认价值计算可持续定价走廊",
)
def build_commercial_pricing_scenario(
    tenant_id: str,
    payload: CommercialPricingScenarioWrite,
    db: DbSession,
    current_user: PlatformAdmin,
) -> CommercialPricingScenarioRead:
    target = CommercialAccessPolicy.require_platform_admin(
        current_user,
        target_tenant_id=tenant_id,
    )
    try:
        return CommercialPricingService(db).build(target, payload)
    except Exception as error:
        raise _http_error(error) from error


def _http_error(error: Exception) -> HTTPException:
    if isinstance(error, LookupError):
        return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(error))
    if isinstance(error, CommercialPermissionError):
        return HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(error))
    if isinstance(error, CommercialConflictError):
        return HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(error))
    if isinstance(error, IntegrityError):
        return HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="商业配置被并发修改或违反数据库唯一性约束，请刷新后重试。",
        )
    if isinstance(error, (CommercialConfigurationError, ValueError)):
        return HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(error))
    raise error
