# app/modules/billing/routes/api/admin_features.py
"""
Admin feature management endpoints.

Provides endpoints for:
- Listing all features with their tier assignments
- Updating tier feature assignments
- Managing feature metadata
- Viewing feature usage statistics

All routes require module access control for the 'billing' module.
"""

import logging

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel
from sqlalchemy.orm import Session

from app.api.deps import get_current_admin_api, require_module_access
from app.core.database import get_db
from app.modules.billing.services.feature_service import feature_service
from app.modules.enums import FrontendType
from models.schema.auth import UserContext

admin_features_router = APIRouter(
    prefix="/features",
    dependencies=[Depends(require_module_access("billing", FrontendType.ADMIN))],
)
logger = logging.getLogger(__name__)


# ============================================================================
# Response Schemas
# ============================================================================


class FeatureResponse(BaseModel):
    """Feature information for admin."""

    id: int
    code: str
    name: str
    description: str | None = None
    category: str
    ui_location: str | None = None
    ui_icon: str | None = None
    ui_route: str | None = None
    ui_badge_text: str | None = None
    minimum_tier_id: int | None = None
    minimum_tier_code: str | None = None
    minimum_tier_name: str | None = None
    is_active: bool
    is_visible: bool
    display_order: int


class FeatureListResponse(BaseModel):
    """List of features."""

    features: list[FeatureResponse]
    total: int


class TierFeaturesResponse(BaseModel):
    """Tier with its features."""

    id: int
    code: str
    name: str
    description: str | None = None
    features: list[str]
    feature_count: int


class TierListWithFeaturesResponse(BaseModel):
    """All tiers with their features."""

    tiers: list[TierFeaturesResponse]


class UpdateTierFeaturesRequest(BaseModel):
    """Request to update tier features."""

    feature_codes: list[str]


class UpdateFeatureRequest(BaseModel):
    """Request to update feature metadata."""

    name: str | None = None
    description: str | None = None
    category: str | None = None
    ui_location: str | None = None
    ui_icon: str | None = None
    ui_route: str | None = None
    ui_badge_text: str | None = None
    minimum_tier_code: str | None = None
    is_active: bool | None = None
    is_visible: bool | None = None
    display_order: int | None = None


class CategoryListResponse(BaseModel):
    """List of feature categories."""

    categories: list[str]


class TierFeatureDetailResponse(BaseModel):
    """Tier features with full details."""

    tier_code: str
    tier_name: str
    features: list[dict]
    feature_count: int


# ============================================================================
# Helper Functions
# ============================================================================


def _feature_to_response(feature) -> FeatureResponse:
    """Convert Feature model to response."""
    return FeatureResponse(
        id=feature.id,
        code=feature.code,
        name=feature.name,
        description=feature.description,
        category=feature.category,
        ui_location=feature.ui_location,
        ui_icon=feature.ui_icon,
        ui_route=feature.ui_route,
        ui_badge_text=feature.ui_badge_text,
        minimum_tier_id=feature.minimum_tier_id,
        minimum_tier_code=feature.minimum_tier.code if feature.minimum_tier else None,
        minimum_tier_name=feature.minimum_tier.name if feature.minimum_tier else None,
        is_active=feature.is_active,
        is_visible=feature.is_visible,
        display_order=feature.display_order,
    )


# ============================================================================
# Endpoints
# ============================================================================


@admin_features_router.get("", response_model=FeatureListResponse)
def list_features(
    category: str | None = Query(None, description="Filter by category"),
    active_only: bool = Query(False, description="Only active features"),
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """List all features with their tier assignments."""
    features = feature_service.get_all_features(
        db, category=category, active_only=active_only
    )

    return FeatureListResponse(
        features=[_feature_to_response(f) for f in features],
        total=len(features),
    )


@admin_features_router.get("/categories", response_model=CategoryListResponse)
def list_categories(
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """List all feature categories."""
    categories = feature_service.get_categories(db)
    return CategoryListResponse(categories=categories)


@admin_features_router.get("/tiers", response_model=TierListWithFeaturesResponse)
def list_tiers_with_features(
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """List all tiers with their feature assignments."""
    tiers = feature_service.get_all_tiers_with_features(db)

    return TierListWithFeaturesResponse(
        tiers=[
            TierFeaturesResponse(
                id=t.id,
                code=t.code,
                name=t.name,
                description=t.description,
                features=t.features or [],
                feature_count=len(t.features or []),
            )
            for t in tiers
        ]
    )


@admin_features_router.get("/{feature_code}", response_model=FeatureResponse)
def get_feature(
    feature_code: str,
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """
    Get a single feature by code.

    Raises 404 if feature not found.
    """
    feature = feature_service.get_feature_by_code(db, feature_code)

    if not feature:
        from app.modules.billing.exceptions import FeatureNotFoundError

        raise FeatureNotFoundError(feature_code)

    return _feature_to_response(feature)


@admin_features_router.put("/{feature_code}", response_model=FeatureResponse)
def update_feature(
    feature_code: str,
    request: UpdateFeatureRequest,
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """
    Update feature metadata.

    Raises 404 if feature not found, 400 if tier code is invalid.
    """
    feature = feature_service.update_feature(
        db,
        feature_code,
        name=request.name,
        description=request.description,
        category=request.category,
        ui_location=request.ui_location,
        ui_icon=request.ui_icon,
        ui_route=request.ui_route,
        ui_badge_text=request.ui_badge_text,
        minimum_tier_code=request.minimum_tier_code,
        is_active=request.is_active,
        is_visible=request.is_visible,
        display_order=request.display_order,
    )

    db.commit()
    db.refresh(feature)

    logger.info(f"Updated feature {feature_code} by admin {current_user.id}")

    return _feature_to_response(feature)


@admin_features_router.put("/tiers/{tier_code}/features", response_model=TierFeaturesResponse)
def update_tier_features(
    tier_code: str,
    request: UpdateTierFeaturesRequest,
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """
    Update features assigned to a tier.

    Raises 404 if tier not found, 422 if any feature codes are invalid.
    """
    tier = feature_service.update_tier_features(db, tier_code, request.feature_codes)
    db.commit()

    logger.info(
        f"Updated tier {tier_code} features to {len(request.feature_codes)} features "
        f"by admin {current_user.id}"
    )

    return TierFeaturesResponse(
        id=tier.id,
        code=tier.code,
        name=tier.name,
        description=tier.description,
        features=tier.features or [],
        feature_count=len(tier.features or []),
    )


@admin_features_router.get("/tiers/{tier_code}/features", response_model=TierFeatureDetailResponse)
def get_tier_features(
    tier_code: str,
    current_user: UserContext = Depends(get_current_admin_api),
    db: Session = Depends(get_db),
):
    """
    Get features assigned to a specific tier with full details.

    Raises 404 if tier not found.
    """
    tier, features = feature_service.get_tier_features_with_details(db, tier_code)

    return TierFeatureDetailResponse(
        tier_code=tier.code,
        tier_name=tier.name,
        features=[
            {
                "code": f.code,
                "name": f.name,
                "category": f.category,
                "description": f.description,
            }
            for f in features
        ],
        feature_count=len(features),
    )
