"""Plans FastAPI dependencies."""

from collections.abc import Callable
from typing import TYPE_CHECKING, Any

from fastapi import Depends, HTTPException, Request, status

from identity_plan_kit.auth.dependencies import CurrentUser
from identity_plan_kit.plans.domain.exceptions import (
    FeatureNotAvailableError,
    PlanExpiredError,
    QuotaExceededError,
    UserPlanNotFoundError,
)
from identity_plan_kit.shared.logging import get_logger

if TYPE_CHECKING:
    from identity_plan_kit import IdentityPlanKit
logger = get_logger(__name__)


def requires_plan(plan_code: str | None = None) -> Callable[..., Any]:
    """
    Dependency that requires user to have an active plan.

    Optionally requires a specific plan.

    Usage:
        @app.get("/pro/feature")
        @requires_plan("pro")
        async def pro_feature(user: CurrentUser):
            ...

        @app.get("/any-plan")
        @requires_plan()
        async def any_plan_feature(user: CurrentUser):
            ...

    Args:
        plan_code: Required plan code (None = any plan)

    Returns:
        FastAPI dependency
    """

    async def dependency(
        request: Request,
        user: CurrentUser,
    ) -> None:
        kit = request.app.state.identity_plan_kit
        plan_service = kit.plan_service

        try:
            user_plan = await plan_service.get_user_plan(user.id)

            if plan_code and user_plan.plan_code != plan_code:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"Required plan: {plan_code}",
                )

        except UserPlanNotFoundError:
            raise HTTPException(
                status_code=status.HTTP_402_PAYMENT_REQUIRED,
                detail="No active subscription plan",
            ) from None
        except PlanExpiredError:
            raise HTTPException(
                status_code=status.HTTP_402_PAYMENT_REQUIRED,
                detail="Subscription plan has expired",
            ) from None

    return Depends(dependency)


def requires_feature(
    feature_code: str,
    consume: int = 0,
) -> Callable[..., Any]:
    """
    Dependency that requires access to a feature and optionally consumes quota.

    Usage:
        @app.post("/api/generate")
        @requires_feature("ai_generation", consume=1)
        async def generate(user: CurrentUser):
            ...

        @app.get("/api/exports")
        @requires_feature("exports")  # Just check access, don't consume
        async def list_exports(user: CurrentUser):
            ...

    Args:
        feature_code: Required feature code
        consume: Amount of quota to consume (0 = just check access)

    Returns:
        FastAPI dependency
    """

    async def dependency(
        request: Request,
        user: CurrentUser,
    ) -> None:
        kit: IdentityPlanKit = request.app.state.identity_plan_kit
        plan_service = kit.plan_service

        try:
            if consume > 0:
                # Check and consume quota
                await plan_service.check_and_consume_quota(
                    user_id=user.id,
                    feature_code=feature_code,
                    amount=consume,
                )
            else:
                # Just check access
                has_access = await plan_service.check_feature_access(
                    user_id=user.id,
                    feature_code=feature_code,
                )
                if not has_access:
                    raise FeatureNotAvailableError(feature_code)  # noqa: TRY301

        except UserPlanNotFoundError:
            raise HTTPException(
                status_code=status.HTTP_402_PAYMENT_REQUIRED,
                detail="No active subscription plan",
            ) from None
        except PlanExpiredError:
            raise HTTPException(
                status_code=status.HTTP_402_PAYMENT_REQUIRED,
                detail="Subscription plan has expired",
            ) from None
        except FeatureNotAvailableError as e:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=str(e),
            ) from None
        except QuotaExceededError as e:
            raise HTTPException(
                status_code=status.HTTP_429_TOO_MANY_REQUESTS,
                detail=str(e),
                headers={
                    "X-Quota-Limit": str(e.limit),
                    "X-Quota-Used": str(e.used),
                    "X-Quota-Remaining": str(e.remaining),
                },
            ) from None

    return Depends(dependency)
