# app/modules/billing/routes/api/store_features.py
"""
Store features API endpoints.

Provides feature availability information for the frontend to:
- Show/hide UI elements based on tier
- Display upgrade prompts for unavailable features
- Load feature metadata for dynamic rendering

Endpoints:
- GET /features/available - List of feature codes (for quick checks)
- GET /features - Full feature list with availability and metadata
- GET /features/{code} - Single feature details with upgrade info
- GET /features/categories - List feature categories
- GET /features/check/{code} - Quick boolean feature check

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

import logging

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

from app.api.deps import get_current_store_api, require_module_access
from app.core.database import get_db
from app.modules.billing.exceptions import FeatureNotFoundException
from app.modules.billing.schemas.billing import (
    CategoryListResponse,
    FeatureCodeListResponse,
    FeatureDetailResponse,
    FeatureGroupedResponse,
    FeatureListResponse,
    FeatureResponse,
    StoreFeatureCheckResponse,
)
from app.modules.billing.services.feature_aggregator import feature_aggregator
from app.modules.billing.services.feature_service import feature_service
from app.modules.billing.services.subscription_service import subscription_service
from app.modules.enums import FrontendType
from app.modules.tenancy.schemas.auth import UserContext

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


# ============================================================================
# Internal Helpers
# ============================================================================


def _get_tier_info(db: Session, store_id: int) -> tuple[str, str]:
    """Get (tier_code, tier_name) for a store's subscription."""
    sub = subscription_service.get_subscription_for_store(db, store_id)
    if sub and sub.tier:
        return sub.tier.code, sub.tier.name
    return "unknown", "Unknown"


def _declaration_to_feature_response(
    decl, is_available: bool
) -> FeatureResponse:
    """Map a FeatureDeclaration to a FeatureResponse."""
    return FeatureResponse(
        code=decl.code,
        name=decl.name_key,
        description=decl.description_key,
        category=decl.category,
        feature_type=decl.feature_type.value if decl.feature_type else None,
        ui_icon=decl.ui_icon,
        is_available=is_available,
    )


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


@store_features_router.get("/available", response_model=FeatureCodeListResponse)
def get_available_features(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get list of feature codes available to store.

    This is a lightweight endpoint for quick feature checks.
    Use this to populate a frontend feature store on app init.

    Returns:
        List of feature codes the store has access to
    """
    store_id = current_user.token_store_id
    merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)

    # Get available feature codes
    feature_codes = feature_service.get_merchant_feature_codes(db, merchant_id, platform_id)

    # Get tier info
    tier_code, tier_name = _get_tier_info(db, store_id)

    return FeatureCodeListResponse(
        features=sorted(feature_codes),
        tier_code=tier_code,
        tier_name=tier_name,
    )


@store_features_router.get("", response_model=FeatureListResponse)
def get_features(
    category: str | None = Query(None, description="Filter by category"),
    include_unavailable: bool = Query(True, description="Include features not available to store"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get all features with availability status and metadata.

    This is a comprehensive endpoint for building feature-gated UIs.
    Each feature includes:
    - Availability status
    - UI metadata (icon)
    - Feature type (binary/quantitative)

    Args:
        category: Filter to specific category (orders, inventory, etc.)
        include_unavailable: Whether to include locked features

    Returns:
        List of features with metadata and availability
    """
    store_id = current_user.token_store_id
    merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)

    # Get all declarations and available codes
    all_declarations = feature_aggregator.get_all_declarations()
    available_codes = feature_service.get_merchant_feature_codes(db, merchant_id, platform_id)

    # Build feature list
    features = []
    for code, decl in sorted(
        all_declarations.items(), key=lambda x: (x[1].category, x[1].display_order)
    ):
        # Filter by category if specified
        if category and decl.category != category:
            continue

        is_available = code in available_codes

        # Skip unavailable if not requested
        if not include_unavailable and not is_available:
            continue

        features.append(_declaration_to_feature_response(decl, is_available))

    available_count = sum(1 for f in features if f.is_available)

    # Get tier info
    tier_code, tier_name = _get_tier_info(db, store_id)

    return FeatureListResponse(
        features=features,
        available_count=available_count,
        total_count=len(features),
        tier_code=tier_code,
        tier_name=tier_name,
    )


@store_features_router.get("/categories", response_model=CategoryListResponse)
def get_feature_categories(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get list of feature categories.

    Returns:
        List of category names
    """
    by_category = feature_aggregator.get_declarations_by_category()
    return CategoryListResponse(categories=sorted(by_category.keys()))


@store_features_router.get("/grouped", response_model=FeatureGroupedResponse)
def get_features_grouped(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get features grouped by category.

    Useful for rendering feature comparison tables or settings pages.
    """
    store_id = current_user.token_store_id
    merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)

    # Get declarations grouped by category and available codes
    by_category = feature_aggregator.get_declarations_by_category()
    available_codes = feature_service.get_merchant_feature_codes(db, merchant_id, platform_id)

    # Convert to response format
    categories_response: dict[str, list[FeatureResponse]] = {}
    total = 0
    available = 0

    for category, declarations in sorted(by_category.items()):
        category_features = []
        for decl in declarations:
            is_available = decl.code in available_codes
            category_features.append(
                _declaration_to_feature_response(decl, is_available)
            )
            total += 1
            if is_available:
                available += 1
        categories_response[category] = category_features

    return FeatureGroupedResponse(
        categories=categories_response,
        available_count=available,
        total_count=total,
    )


@store_features_router.get("/check/{feature_code}", response_model=StoreFeatureCheckResponse)
def check_feature(
    feature_code: str,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Quick check if store has access to a feature.

    Returns simple boolean response for inline checks.
    Uses has_feature_for_store which resolves store -> merchant internally.

    Args:
        feature_code: The feature code

    Returns:
        has_feature and feature_code
    """
    store_id = current_user.token_store_id
    has = feature_service.has_feature_for_store(
        db, store_id, feature_code, platform_id=current_user.token_platform_id
    )

    return StoreFeatureCheckResponse(has_feature=has, feature_code=feature_code)


@store_features_router.get("/{feature_code}", response_model=FeatureDetailResponse)
def get_feature_detail(
    feature_code: str,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Get detailed information about a specific feature.

    Includes upgrade information if the feature is not available.
    Use this for upgrade prompts and feature explanation modals.

    Args:
        feature_code: The feature code

    Returns:
        Feature details with upgrade info if locked
    """
    store_id = current_user.token_store_id
    merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)

    # Get feature declaration
    decl = feature_aggregator.get_declaration(feature_code)
    if not decl:
        raise FeatureNotFoundException(feature_code)

    # Check availability
    is_available = feature_service.has_feature(db, merchant_id, platform_id, feature_code)

    # Build response
    return FeatureDetailResponse(
        code=decl.code,
        name=decl.name_key,
        description=decl.description_key,
        category=decl.category,
        feature_type=decl.feature_type.value if decl.feature_type else None,
        ui_icon=decl.ui_icon,
        is_available=is_available,
        # Upgrade info fields are left as None since the new service
        # does not provide tier-comparison upgrade suggestions.
        # This can be extended when upgrade flow is implemented.
    )
