from datetime import datetime, timedelta
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from uuid import UUID

from app.database import get_db
from app.models.tenant import Tenant
from app.models.device import Device
from app.models.user import User
from app.api.deps import get_current_user, require_super_admin
from pydantic import BaseModel

router = APIRouter()


class SubscriptionPlan(BaseModel):
    name: str
    max_devices: int
    max_sensors: int
    max_users: int
    price_monthly: float
    price_yearly: float


class SubscriptionUpdate(BaseModel):
    subscription_plan: Optional[str] = None
    max_devices: Optional[int] = None
    max_sensors: Optional[int] = None
    max_users: Optional[int] = None
    subscription_end: Optional[datetime] = None
    is_subscription_active: Optional[bool] = None
    auto_renew: Optional[bool] = None


class SubscriptionRenew(BaseModel):
    months: int = 1


class SubscriptionResponse(BaseModel):
    tenant_id: UUID
    tenant_name: str
    subscription_plan: str
    max_devices: int
    max_sensors: int
    max_users: int
    current_devices: int
    current_sensors: int
    current_users: int
    subscription_start: Optional[datetime]
    subscription_end: Optional[datetime]
    is_subscription_active: bool
    auto_renew: bool
    days_remaining: Optional[int]
    is_expired: bool

    class Config:
        from_attributes = True


# Predefined subscription plans
SUBSCRIPTION_PLANS = {
    "free": SubscriptionPlan(
        name="Free",
        max_devices=5,
        max_sensors=10,
        max_users=1,
        price_monthly=0,
        price_yearly=0
    ),
    "basic": SubscriptionPlan(
        name="Basic",
        max_devices=20,
        max_sensors=50,
        max_users=3,
        price_monthly=99,
        price_yearly=999
    ),
    "professional": SubscriptionPlan(
        name="Professional",
        max_devices=50,
        max_sensors=150,
        max_users=10,
        price_monthly=299,
        price_yearly=2999
    ),
    "enterprise": SubscriptionPlan(
        name="Enterprise",
        max_devices=200,
        max_sensors=500,
        max_users=50,
        price_monthly=999,
        price_yearly=9999
    ),
    "unlimited": SubscriptionPlan(
        name="Unlimited",
        max_devices=99999,
        max_sensors=99999,
        max_users=99999,
        price_monthly=2999,
        price_yearly=29999
    ),
}


@router.get("/plans")
async def get_subscription_plans():
    """الحصول على قائمة خطط الاشتراك المتاحة"""
    return SUBSCRIPTION_PLANS


@router.get("/tenant/{tenant_id}", response_model=SubscriptionResponse)
async def get_tenant_subscription(
    tenant_id: UUID,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """الحصول على تفاصيل اشتراك عميل معين"""
    result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
    tenant = result.scalar_one_or_none()
    
    if not tenant:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Tenant not found"
        )
    
    # Get current counts
    devices_count = await db.execute(
        select(func.count(Device.id)).where(Device.tenant_id == tenant_id)
    )
    current_devices = devices_count.scalar() or 0
    
    # For sensors, we count devices with type containing 'sensor'
    sensors_count = await db.execute(
        select(func.count(Device.id)).where(
            Device.tenant_id == tenant_id,
            Device.device_type.ilike('%sensor%')
        )
    )
    current_sensors = sensors_count.scalar() or 0
    
    users_count = await db.execute(
        select(func.count(User.id)).where(User.tenant_id == tenant_id)
    )
    current_users = users_count.scalar() or 0
    
    # Calculate days remaining
    days_remaining = None
    is_expired = False
    if tenant.subscription_end:
        delta = tenant.subscription_end - datetime.utcnow()
        days_remaining = max(0, delta.days)
        is_expired = delta.total_seconds() < 0
    
    return SubscriptionResponse(
        tenant_id=tenant.id,
        tenant_name=tenant.name,
        subscription_plan=tenant.subscription_plan,
        max_devices=tenant.max_devices,
        max_sensors=tenant.max_sensors,
        max_users=tenant.max_users,
        current_devices=current_devices,
        current_sensors=current_sensors,
        current_users=current_users,
        subscription_start=tenant.subscription_start,
        subscription_end=tenant.subscription_end,
        is_subscription_active=tenant.is_subscription_active,
        auto_renew=tenant.auto_renew,
        days_remaining=days_remaining,
        is_expired=is_expired
    )


@router.patch("/tenant/{tenant_id}")
async def update_tenant_subscription(
    tenant_id: UUID,
    subscription: SubscriptionUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """تحديث اشتراك عميل"""
    result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
    tenant = result.scalar_one_or_none()
    
    if not tenant:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Tenant not found"
        )
    
    update_data = subscription.model_dump(exclude_unset=True)
    
    # If changing plan, update limits from predefined plans
    if "subscription_plan" in update_data:
        plan_name = update_data["subscription_plan"]
        if plan_name in SUBSCRIPTION_PLANS:
            plan = SUBSCRIPTION_PLANS[plan_name]
            if "max_devices" not in update_data:
                update_data["max_devices"] = plan.max_devices
            if "max_sensors" not in update_data:
                update_data["max_sensors"] = plan.max_sensors
            if "max_users" not in update_data:
                update_data["max_users"] = plan.max_users
    
    for key, value in update_data.items():
        setattr(tenant, key, value)
    
    await db.commit()
    await db.refresh(tenant)
    
    return {"message": "Subscription updated successfully", "tenant_id": str(tenant.id)}


@router.post("/tenant/{tenant_id}/activate")
async def activate_tenant_subscription(
    tenant_id: UUID,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """تفعيل اشتراك عميل"""
    result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
    tenant = result.scalar_one_or_none()
    
    if not tenant:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Tenant not found"
        )
    
    tenant.is_subscription_active = True
    tenant.is_active = True
    await db.commit()
    
    return {"message": "Subscription activated successfully"}


@router.post("/tenant/{tenant_id}/deactivate")
async def deactivate_tenant_subscription(
    tenant_id: UUID,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """إيقاف اشتراك عميل"""
    result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
    tenant = result.scalar_one_or_none()
    
    if not tenant:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Tenant not found"
        )
    
    tenant.is_subscription_active = False
    await db.commit()
    
    return {"message": "Subscription deactivated successfully"}


@router.post("/tenant/{tenant_id}/renew")
async def renew_tenant_subscription(
    tenant_id: UUID,
    renew_data: SubscriptionRenew,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """تجديد اشتراك عميل"""
    result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
    tenant = result.scalar_one_or_none()
    
    if not tenant:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Tenant not found"
        )
    
    # Calculate new end date
    if tenant.subscription_end and tenant.subscription_end > datetime.utcnow():
        # Extend from current end date
        new_end = tenant.subscription_end + timedelta(days=30 * renew_data.months)
    else:
        # Start fresh from now
        tenant.subscription_start = datetime.utcnow()
        new_end = datetime.utcnow() + timedelta(days=30 * renew_data.months)
    
    tenant.subscription_end = new_end
    tenant.is_subscription_active = True
    await db.commit()
    
    return {
        "message": f"Subscription renewed for {renew_data.months} month(s)",
        "new_end_date": new_end.isoformat()
    }


@router.get("/expiring")
async def get_expiring_subscriptions(
    days: int = Query(default=30, description="Days until expiration"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """الحصول على قائمة الاشتراكات التي ستنتهي قريباً"""
    threshold = datetime.utcnow() + timedelta(days=days)
    
    result = await db.execute(
        select(Tenant).where(
            Tenant.subscription_end <= threshold,
            Tenant.subscription_end >= datetime.utcnow(),
            Tenant.is_subscription_active == True
        ).order_by(Tenant.subscription_end)
    )
    tenants = result.scalars().all()
    
    expiring = []
    for tenant in tenants:
        days_remaining = (tenant.subscription_end - datetime.utcnow()).days
        expiring.append({
            "tenant_id": str(tenant.id),
            "tenant_name": tenant.name,
            "subscription_plan": tenant.subscription_plan,
            "subscription_end": tenant.subscription_end.isoformat(),
            "days_remaining": days_remaining,
            "auto_renew": tenant.auto_renew
        })
    
    return expiring


@router.get("/expired")
async def get_expired_subscriptions(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """الحصول على قائمة الاشتراكات المنتهية"""
    result = await db.execute(
        select(Tenant).where(
            Tenant.subscription_end < datetime.utcnow(),
            Tenant.is_subscription_active == True
        ).order_by(Tenant.subscription_end.desc())
    )
    tenants = result.scalars().all()
    
    expired = []
    for tenant in tenants:
        days_expired = (datetime.utcnow() - tenant.subscription_end).days
        expired.append({
            "tenant_id": str(tenant.id),
            "tenant_name": tenant.name,
            "subscription_plan": tenant.subscription_plan,
            "subscription_end": tenant.subscription_end.isoformat(),
            "days_expired": days_expired,
            "auto_renew": tenant.auto_renew
        })
    
    return expired


@router.get("/stats")
async def get_subscription_stats(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_super_admin())
):
    """إحصائيات الاشتراكات"""
    # Total tenants
    total_result = await db.execute(select(func.count(Tenant.id)))
    total_tenants = total_result.scalar() or 0
    
    # Active subscriptions
    active_result = await db.execute(
        select(func.count(Tenant.id)).where(Tenant.is_subscription_active == True)
    )
    active_subscriptions = active_result.scalar() or 0
    
    # Inactive subscriptions
    inactive_subscriptions = total_tenants - active_subscriptions
    
    # Expiring in 30 days
    threshold = datetime.utcnow() + timedelta(days=30)
    expiring_result = await db.execute(
        select(func.count(Tenant.id)).where(
            Tenant.subscription_end <= threshold,
            Tenant.subscription_end >= datetime.utcnow(),
            Tenant.is_subscription_active == True
        )
    )
    expiring_soon = expiring_result.scalar() or 0
    
    # By plan
    plans_result = await db.execute(
        select(Tenant.subscription_plan, func.count(Tenant.id))
        .group_by(Tenant.subscription_plan)
    )
    by_plan = {row[0]: row[1] for row in plans_result.all()}
    
    return {
        "total_tenants": total_tenants,
        "active_subscriptions": active_subscriptions,
        "inactive_subscriptions": inactive_subscriptions,
        "expiring_in_30_days": expiring_soon,
        "by_plan": by_plan
    }
