"""
Subscription Management API Endpoints
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime, date
from decimal import Decimal

from app.database import get_db
from app.auth.dependencies import get_current_user, get_current_admin
from app.models.user import User
from app.models.subscription import Subscription, ServiceType, SubscriptionStatus, PlanTier

router = APIRouter()


# Plan configurations
PLANS = {
    "chatbot": {
        "free": {"price": 0, "messages": 100, "features": ["basic_chat"]},
        "starter": {"price": 2999, "messages": 5000, "features": ["basic_chat", "analytics"]},
        "professional": {"price": 7999, "messages": 25000, "features": ["basic_chat", "analytics", "custom_branding", "api_access"]},
        "enterprise": {"price": 19999, "messages": 100000, "features": ["basic_chat", "analytics", "custom_branding", "api_access", "priority_support", "dedicated_manager"]}
    },
    "voice_agent": {
        "starter": {"price": 4999, "minutes": 500, "features": ["basic_calls"]},
        "professional": {"price": 12999, "minutes": 2000, "features": ["basic_calls", "analytics", "recording"]},
        "enterprise": {"price": 29999, "minutes": 10000, "features": ["basic_calls", "analytics", "recording", "custom_voice"]}
    },
    "document_intelligence": {
        "starter": {"price": 1999, "documents": 500, "features": ["ocr", "extraction"]},
        "professional": {"price": 4999, "documents": 2500, "features": ["ocr", "extraction", "templates", "api_access"]},
        "enterprise": {"price": 14999, "documents": 10000, "features": ["ocr", "extraction", "templates", "api_access", "custom_models"]}
    }
}


# Request/Response Models
class SubscriptionCreate(BaseModel):
    client_id: int
    service_type: str
    plan_tier: str
    billing_cycle: str = "monthly"


class SubscriptionUpdate(BaseModel):
    plan_tier: Optional[str] = None
    status: Optional[str] = None
    auto_renew: Optional[bool] = None


class SubscriptionResponse(BaseModel):
    id: int
    client_id: int
    service_type: str
    plan_tier: str
    plan_name: str
    price_monthly: float
    billing_cycle: str
    currency: str
    status: str
    start_date: date
    end_date: Optional[date]
    next_billing_date: Optional[date]
    auto_renew: bool
    usage_limits: dict
    current_usage: dict
    features: list
    is_active: bool
    is_trial: bool
    created_at: datetime

    class Config:
        from_attributes = True


class SubscriptionListResponse(BaseModel):
    subscriptions: List[SubscriptionResponse]
    total: int
    page: int
    page_size: int


@router.get("/plans")
async def get_available_plans():
    """
    Get all available subscription plans
    """
    return {
        "plans": PLANS,
        "services": list(PLANS.keys())
    }


@router.get("", response_model=SubscriptionListResponse)
async def list_subscriptions(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    service_type: Optional[str] = None,
    status: Optional[str] = None,
    client_id: Optional[int] = None,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    List subscriptions (Admin sees all, clients see their own)
    """
    query = select(Subscription)

    # Non-admins can only see their own client's subscriptions
    if not current_user.is_admin:
        query = query.where(Subscription.client_id == current_user.client_id)
    elif client_id:
        query = query.where(Subscription.client_id == client_id)

    # Apply filters
    if service_type:
        query = query.where(Subscription.service_type == service_type)
    if status:
        query = query.where(Subscription.status == status)

    # Get total count
    count_query = select(func.count()).select_from(query.subquery())
    total = await db.scalar(count_query)

    # Apply pagination
    query = query.offset((page - 1) * page_size).limit(page_size)
    query = query.order_by(Subscription.created_at.desc())

    result = await db.execute(query)
    subscriptions = result.scalars().all()

    return SubscriptionListResponse(
        subscriptions=[SubscriptionResponse(
            id=s.id,
            client_id=s.client_id,
            service_type=s.service_type,
            plan_tier=s.plan_tier,
            plan_name=s.plan_name,
            price_monthly=float(s.price_monthly),
            billing_cycle=s.billing_cycle,
            currency=s.currency,
            status=s.status,
            start_date=s.start_date,
            end_date=s.end_date,
            next_billing_date=s.next_billing_date,
            auto_renew=s.auto_renew,
            usage_limits=s.usage_limits or {},
            current_usage=s.current_usage or {},
            features=s.features or [],
            is_active=s.is_active,
            is_trial=s.is_trial,
            created_at=s.created_at
        ) for s in subscriptions],
        total=total,
        page=page,
        page_size=page_size
    )


@router.get("/my-subscriptions", response_model=List[SubscriptionResponse])
async def get_my_subscriptions(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Get current user's client subscriptions
    """
    if not current_user.client_id:
        return []

    result = await db.execute(
        select(Subscription)
        .where(Subscription.client_id == current_user.client_id)
        .order_by(Subscription.created_at.desc())
    )
    subscriptions = result.scalars().all()

    return [SubscriptionResponse(
        id=s.id,
        client_id=s.client_id,
        service_type=s.service_type,
        plan_tier=s.plan_tier,
        plan_name=s.plan_name,
        price_monthly=float(s.price_monthly),
        billing_cycle=s.billing_cycle,
        currency=s.currency,
        status=s.status,
        start_date=s.start_date,
        end_date=s.end_date,
        next_billing_date=s.next_billing_date,
        auto_renew=s.auto_renew,
        usage_limits=s.usage_limits or {},
        current_usage=s.current_usage or {},
        features=s.features or [],
        is_active=s.is_active,
        is_trial=s.is_trial,
        created_at=s.created_at
    ) for s in subscriptions]


@router.get("/{subscription_id}", response_model=SubscriptionResponse)
async def get_subscription(
    subscription_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Get a specific subscription
    """
    result = await db.execute(select(Subscription).where(Subscription.id == subscription_id))
    subscription = result.scalar_one_or_none()

    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Subscription not found"
        )

    # Check permissions
    if not current_user.is_admin and current_user.client_id != subscription.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    return SubscriptionResponse(
        id=subscription.id,
        client_id=subscription.client_id,
        service_type=subscription.service_type,
        plan_tier=subscription.plan_tier,
        plan_name=subscription.plan_name,
        price_monthly=float(subscription.price_monthly),
        billing_cycle=subscription.billing_cycle,
        currency=subscription.currency,
        status=subscription.status,
        start_date=subscription.start_date,
        end_date=subscription.end_date,
        next_billing_date=subscription.next_billing_date,
        auto_renew=subscription.auto_renew,
        usage_limits=subscription.usage_limits or {},
        current_usage=subscription.current_usage or {},
        features=subscription.features or [],
        is_active=subscription.is_active,
        is_trial=subscription.is_trial,
        created_at=subscription.created_at
    )


@router.post("", response_model=SubscriptionResponse, status_code=status.HTTP_201_CREATED)
async def create_subscription(
    data: SubscriptionCreate,
    current_user: User = Depends(get_current_admin),
    db: AsyncSession = Depends(get_db)
):
    """
    Create a new subscription (Admin only)
    """
    # Validate service and plan
    if data.service_type not in PLANS:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid service type. Available: {list(PLANS.keys())}"
        )

    if data.plan_tier not in PLANS[data.service_type]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid plan tier for {data.service_type}"
        )

    plan = PLANS[data.service_type][data.plan_tier]

    # Build usage limits based on plan
    usage_limits = {}
    if "messages" in plan:
        usage_limits["messages_per_month"] = plan["messages"]
    if "minutes" in plan:
        usage_limits["minutes_per_month"] = plan["minutes"]
    if "documents" in plan:
        usage_limits["documents_per_month"] = plan["documents"]

    subscription = Subscription(
        client_id=data.client_id,
        service_type=data.service_type,
        plan_tier=data.plan_tier,
        plan_name=f"{data.service_type.replace('_', ' ').title()} - {data.plan_tier.title()}",
        price_monthly=Decimal(plan["price"]),
        billing_cycle=data.billing_cycle,
        currency="INR",
        status=SubscriptionStatus.ACTIVE,
        start_date=date.today(),
        usage_limits=usage_limits,
        current_usage={},
        features=plan["features"],
        auto_renew=True
    )
    db.add(subscription)
    await db.commit()
    await db.refresh(subscription)

    return SubscriptionResponse(
        id=subscription.id,
        client_id=subscription.client_id,
        service_type=subscription.service_type,
        plan_tier=subscription.plan_tier,
        plan_name=subscription.plan_name,
        price_monthly=float(subscription.price_monthly),
        billing_cycle=subscription.billing_cycle,
        currency=subscription.currency,
        status=subscription.status,
        start_date=subscription.start_date,
        end_date=subscription.end_date,
        next_billing_date=subscription.next_billing_date,
        auto_renew=subscription.auto_renew,
        usage_limits=subscription.usage_limits or {},
        current_usage=subscription.current_usage or {},
        features=subscription.features or [],
        is_active=subscription.is_active,
        is_trial=subscription.is_trial,
        created_at=subscription.created_at
    )


@router.put("/{subscription_id}", response_model=SubscriptionResponse)
async def update_subscription(
    subscription_id: int,
    data: SubscriptionUpdate,
    current_user: User = Depends(get_current_admin),
    db: AsyncSession = Depends(get_db)
):
    """
    Update a subscription (Admin only)
    """
    result = await db.execute(select(Subscription).where(Subscription.id == subscription_id))
    subscription = result.scalar_one_or_none()

    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Subscription not found"
        )

    # Update fields
    if data.plan_tier is not None:
        subscription.plan_tier = data.plan_tier
    if data.status is not None:
        subscription.status = data.status
    if data.auto_renew is not None:
        subscription.auto_renew = data.auto_renew

    await db.commit()
    await db.refresh(subscription)

    return SubscriptionResponse(
        id=subscription.id,
        client_id=subscription.client_id,
        service_type=subscription.service_type,
        plan_tier=subscription.plan_tier,
        plan_name=subscription.plan_name,
        price_monthly=float(subscription.price_monthly),
        billing_cycle=subscription.billing_cycle,
        currency=subscription.currency,
        status=subscription.status,
        start_date=subscription.start_date,
        end_date=subscription.end_date,
        next_billing_date=subscription.next_billing_date,
        auto_renew=subscription.auto_renew,
        usage_limits=subscription.usage_limits or {},
        current_usage=subscription.current_usage or {},
        features=subscription.features or [],
        is_active=subscription.is_active,
        is_trial=subscription.is_trial,
        created_at=subscription.created_at
    )


@router.post("/{subscription_id}/cancel")
async def cancel_subscription(
    subscription_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Cancel a subscription
    """
    result = await db.execute(select(Subscription).where(Subscription.id == subscription_id))
    subscription = result.scalar_one_or_none()

    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Subscription not found"
        )

    # Check permissions
    if not current_user.is_admin and current_user.client_id != subscription.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    subscription.status = SubscriptionStatus.CANCELLED
    subscription.cancelled_at = date.today()
    subscription.auto_renew = False

    await db.commit()

    return {"message": "Subscription cancelled successfully"}


@router.get("/{subscription_id}/usage")
async def get_subscription_usage(
    subscription_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Get usage details for a subscription
    """
    result = await db.execute(select(Subscription).where(Subscription.id == subscription_id))
    subscription = result.scalar_one_or_none()

    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Subscription not found"
        )

    # Check permissions
    if not current_user.is_admin and current_user.client_id != subscription.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    # Calculate usage percentages
    usage_details = {}
    for metric, limit in (subscription.usage_limits or {}).items():
        used = (subscription.current_usage or {}).get(metric, 0)
        percentage = round((used / limit) * 100, 2) if limit > 0 else 0
        usage_details[metric] = {
            "used": used,
            "limit": limit,
            "percentage": percentage,
            "remaining": limit - used
        }

    return {
        "subscription_id": subscription.id,
        "service_type": subscription.service_type,
        "plan_tier": subscription.plan_tier,
        "billing_cycle": subscription.billing_cycle,
        "usage": usage_details
    }
