"""
Subscription Limit Service
Service for validating tenant actions against subscription limits and features
"""

import structlog
from typing import Dict, Any, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import HTTPException, status
import httpx

from app.repositories import SubscriptionRepository, TenantRepository, TenantMemberRepository
from app.models.tenants import Subscription, Tenant, TenantMember
from shared.database.exceptions import DatabaseError
from shared.database.base import create_database_manager

logger = structlog.get_logger()


class SubscriptionLimitService:
    """Service for validating subscription limits and features"""
    
    def __init__(self, database_manager=None):
        self.database_manager = database_manager or create_database_manager()
    
    async def _init_repositories(self, session):
        """Initialize repositories with session"""
        self.subscription_repo = SubscriptionRepository(Subscription, session)
        self.tenant_repo = TenantRepository(Tenant, session)
        self.member_repo = TenantMemberRepository(TenantMember, session)
        return {
            'subscription': self.subscription_repo,
            'tenant': self.tenant_repo,
            'member': self.member_repo
        }
    
    async def get_tenant_subscription_limits(self, tenant_id: str) -> Dict[str, Any]:
        """Get current subscription limits for a tenant"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    # Return basic limits if no subscription
                    return {
                        "plan": "starter",
                        "max_users": 5,
                        "max_locations": 1,
                        "max_products": 50,
                        "features": {
                            "inventory_management": "basic",
                            "demand_prediction": "basic",
                            "production_reports": "basic",
                            "analytics": "basic",
                            "support": "email",
                            "ai_model_configuration": "basic"  # Added AI model configuration for all tiers
                        }
                    }
                
                return {
                    "plan": subscription.plan,
                    "max_users": subscription.max_users,
                    "max_locations": subscription.max_locations,
                    "max_products": subscription.max_products,
                    "features": subscription.features or {}
                }
                
        except Exception as e:
            logger.error("Failed to get subscription limits",
                        tenant_id=tenant_id,
                        error=str(e))
            # Return basic limits on error
            return {
                "plan": "starter",
                "max_users": 5,
                "max_locations": 1,
                "max_products": 50,
                "features": {}
            }
    
    async def can_add_location(self, tenant_id: str) -> Dict[str, Any]:
        """Check if tenant can add another location"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                # Get subscription limits
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return {"can_add": False, "reason": "No active subscription"}
                
                # Check if unlimited locations (-1)
                if subscription.max_locations == -1:
                    return {"can_add": True, "reason": "Unlimited locations allowed"}
                
                # Count current locations (this would need to be implemented based on your location model)
                # For now, we'll assume 1 location per tenant as default
                current_locations = 1  # TODO: Implement actual location count
                
                can_add = current_locations < subscription.max_locations
                return {
                    "can_add": can_add,
                    "current_count": current_locations,
                    "max_allowed": subscription.max_locations,
                    "reason": "Within limits" if can_add else f"Maximum {subscription.max_locations} locations allowed for {subscription.plan} plan"
                }
                
        except Exception as e:
            logger.error("Failed to check location limits",
                        tenant_id=tenant_id,
                        error=str(e))
            return {"can_add": False, "reason": "Error checking limits"}
    
    async def can_add_product(self, tenant_id: str) -> Dict[str, Any]:
        """Check if tenant can add another product"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                # Get subscription limits
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return {"can_add": False, "reason": "No active subscription"}
                
                # Check if unlimited products (-1)
                if subscription.max_products == -1:
                    return {"can_add": True, "reason": "Unlimited products allowed"}
                
                # Count current products (this would need to be implemented based on your product model)
                # For now, we'll return a placeholder
                current_products = 0  # TODO: Implement actual product count
                
                can_add = current_products < subscription.max_products
                return {
                    "can_add": can_add,
                    "current_count": current_products,
                    "max_allowed": subscription.max_products,
                    "reason": "Within limits" if can_add else f"Maximum {subscription.max_products} products allowed for {subscription.plan} plan"
                }
                
        except Exception as e:
            logger.error("Failed to check product limits",
                        tenant_id=tenant_id,
                        error=str(e))
            return {"can_add": False, "reason": "Error checking limits"}
    
    async def can_add_user(self, tenant_id: str) -> Dict[str, Any]:
        """Check if tenant can add another user/member"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                # Get subscription limits
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return {"can_add": False, "reason": "No active subscription"}
                
                # Check if unlimited users (-1)
                if subscription.max_users == -1:
                    return {"can_add": True, "reason": "Unlimited users allowed"}
                
                # Count current active members
                members = await self.member_repo.get_tenant_members(tenant_id, active_only=True)
                current_users = len(members)
                
                can_add = current_users < subscription.max_users
                return {
                    "can_add": can_add,
                    "current_count": current_users,
                    "max_allowed": subscription.max_users,
                    "reason": "Within limits" if can_add else f"Maximum {subscription.max_users} users allowed for {subscription.plan} plan"
                }
                
        except Exception as e:
            logger.error("Failed to check user limits",
                        tenant_id=tenant_id,
                        error=str(e))
            return {"can_add": False, "reason": "Error checking limits"}
    
    async def has_feature(self, tenant_id: str, feature: str) -> Dict[str, Any]:
        """Check if tenant has access to a specific feature"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return {"has_feature": False, "reason": "No active subscription"}
                
                features = subscription.features or {}
                has_feature = feature in features
                
                return {
                    "has_feature": has_feature,
                    "feature_value": features.get(feature),
                    "plan": subscription.plan,
                    "reason": "Feature available" if has_feature else f"Feature '{feature}' not available in {subscription.plan} plan"
                }
                
        except Exception as e:
            logger.error("Failed to check feature access",
                        tenant_id=tenant_id,
                        feature=feature,
                        error=str(e))
            return {"has_feature": False, "reason": "Error checking feature access"}
    
    async def get_feature_level(self, tenant_id: str, feature: str) -> Optional[str]:
        """Get the level/type of a feature for a tenant"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return None
                
                features = subscription.features or {}
                return features.get(feature)
                
        except Exception as e:
            logger.error("Failed to get feature level",
                        tenant_id=tenant_id,
                        feature=feature,
                        error=str(e))
            return None
    
    async def validate_plan_upgrade(self, tenant_id: str, new_plan: str) -> Dict[str, Any]:
        """Validate if a tenant can upgrade to a new plan"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                # Get current subscription
                current_subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not current_subscription:
                    return {"can_upgrade": True, "reason": "No current subscription, can start with any plan"}
                
                # Define plan hierarchy
                plan_hierarchy = {"starter": 1, "professional": 2, "enterprise": 3}
                
                current_level = plan_hierarchy.get(current_subscription.plan, 0)
                new_level = plan_hierarchy.get(new_plan, 0)
                
                if new_level == 0:
                    return {"can_upgrade": False, "reason": f"Invalid plan: {new_plan}"}
                
                # Check current usage against new plan limits
                from app.repositories.subscription_repository import SubscriptionRepository
                temp_repo = SubscriptionRepository(Subscription, db_session)
                new_plan_config = temp_repo._get_plan_configuration(new_plan)
                
                # Check if current usage fits new plan
                members = await self.member_repo.get_tenant_members(tenant_id, active_only=True)
                current_users = len(members)
                
                if new_plan_config["max_users"] != -1 and current_users > new_plan_config["max_users"]:
                    return {
                        "can_upgrade": False,
                        "reason": f"Current usage ({current_users} users) exceeds {new_plan} plan limits ({new_plan_config['max_users']} users)"
                    }
                
                return {
                    "can_upgrade": True,
                    "current_plan": current_subscription.plan,
                    "new_plan": new_plan,
                    "price_change": new_plan_config["monthly_price"] - current_subscription.monthly_price,
                    "new_features": new_plan_config.get("features", {}),
                    "reason": "Upgrade validation successful"
                }
                
        except Exception as e:
            logger.error("Failed to validate plan upgrade",
                        tenant_id=tenant_id,
                        new_plan=new_plan,
                        error=str(e))
            return {"can_upgrade": False, "reason": "Error validating upgrade"}
    
    async def get_usage_summary(self, tenant_id: str) -> Dict[str, Any]:
        """Get a summary of current usage vs limits for a tenant"""
        try:
            async with self.database_manager.get_session() as db_session:
                await self._init_repositories(db_session)
                
                subscription = await self.subscription_repo.get_active_subscription(tenant_id)
                if not subscription:
                    return {"error": "No active subscription"}
                
                # Get current usage
                members = await self.member_repo.get_tenant_members(tenant_id, active_only=True)
                current_users = len(members)

                # Get actual ingredient/product count from inventory service
                current_products = await self._get_ingredient_count(tenant_id)

                # TODO: Implement actual location count
                current_locations = 1
                
                return {
                    "plan": subscription.plan,
                    "monthly_price": subscription.monthly_price,
                    "status": subscription.status,
                    "usage": {
                        "users": {
                            "current": current_users,
                            "limit": subscription.max_users,
                            "unlimited": subscription.max_users == -1,
                            "usage_percentage": 0 if subscription.max_users == -1 else (current_users / subscription.max_users) * 100
                        },
                        "locations": {
                            "current": current_locations,
                            "limit": subscription.max_locations,
                            "unlimited": subscription.max_locations == -1,
                            "usage_percentage": 0 if subscription.max_locations == -1 else (current_locations / subscription.max_locations) * 100
                        },
                        "products": {
                            "current": current_products,
                            "limit": subscription.max_products,
                            "unlimited": subscription.max_products == -1,
                            "usage_percentage": 0 if subscription.max_products == -1 else (current_products / subscription.max_products) * 100 if subscription.max_products > 0 else 0
                        }
                    },
                    "features": subscription.features or {},
                    "next_billing_date": subscription.next_billing_date.isoformat() if subscription.next_billing_date else None,
                    "trial_ends_at": subscription.trial_ends_at.isoformat() if subscription.trial_ends_at else None
                }
                
        except Exception as e:
            logger.error("Failed to get usage summary",
                        tenant_id=tenant_id,
                        error=str(e))
            return {"error": "Failed to get usage summary"}

    async def _get_ingredient_count(self, tenant_id: str) -> int:
        """Get ingredient count from inventory service using shared client"""
        try:
            from app.core.config import settings
            from shared.clients.inventory_client import create_inventory_client

            # Use the shared inventory client with proper authentication
            inventory_client = create_inventory_client(settings)
            count = await inventory_client.count_ingredients(tenant_id)

            logger.info(
                "Retrieved ingredient count via inventory client",
                tenant_id=tenant_id,
                count=count
            )
            return count

        except Exception as e:
            logger.error(
                "Error getting ingredient count via inventory client",
                tenant_id=tenant_id,
                error=str(e)
            )
            # Return 0 as fallback to avoid breaking subscription display
            return 0


# Legacy alias for backward compatibility
SubscriptionService = SubscriptionLimitService