"""
Fee calculation engine for broker billing
"""

import logging
from datetime import datetime, date
from typing import Dict, Any, Optional, List
from decimal import Decimal, Decimal as Dec

logger = logging.getLogger(__name__)


class FeeCalculator:
    """
    Calculates fees for broker subscriptions based on plan type and usage.
    
    Fee Types:
    - Transaction Fee: Fixed fee per transaction (configurable per plan)
    - Revenue Share: Percentage of revenue generated (configurable per plan)
    - Monthly Fee: Fixed monthly subscription fee (configurable per plan)
    """
    
    # Plan type constants
    PLAN_FREE = 'free'
    PLAN_BASIC = 'basic'
    PLAN_PROFESSIONAL = 'professional'
    PLAN_ENTERPRISE = 'enterprise'
    
    # Transaction type constants
    TXN_TYPE_MONTHLY_FEE = 'monthly_fee'
    TXN_TYPE_TRANSACTION_FEE = 'transaction_fee'
    TXN_TYPE_REVENUE_SHARE = 'revenue_share'
    TXN_TYPE_PAYMENT = 'payment'
    TXN_TYPE_REFUND = 'refund'
    TXN_TYPE_ADJUSTMENT = 'adjustment'
    
    def __init__(self, db_manager):
        """
        Initialize fee calculator.
        
        Args:
            db_manager: Database manager instance
        """
        self.db_manager = db_manager
        logger.info("FeeCalculator initialized")
    
    def calculate_transaction_fee(self, subscription: Dict[str, Any], 
                                   transaction_amount: Decimal,
                                   currency: str = 'USD') -> Dict[str, Any]:
        """
        Calculate transaction fee for a given transaction amount.
        
        Args:
            subscription: Broker subscription dict with fee settings
            transaction_amount: The transaction amount to calculate fee on
            currency: Currency of the transaction
            
        Returns:
            Dict with fee details:
            {
                'fee_amount': Decimal,
                'fee_currency': str,
                'original_amount': Decimal,
                'original_currency': str,
                'fee_rate': Decimal,
                'plan_type': str
            }
        """
        try:
            # Get fee rate from subscription
            fee_rate = Dec(str(subscription.get('transaction_fee', 0)))
            fee_currency = subscription.get('transaction_fee_currency', 'USD')
            plan_type = subscription.get('plan_type', self.PLAN_FREE)
            
            # Convert amount to fee currency if needed
            if currency != fee_currency:
                from .currency_converter import CurrencyConverter
                converter = CurrencyConverter(self.db_manager)
                transaction_amount = converter.convert(
                    transaction_amount, currency, fee_currency
                )
            
            # Calculate fee
            fee_amount = transaction_amount * fee_rate
            
            return {
                'fee_amount': fee_amount,
                'fee_currency': fee_currency,
                'original_amount': transaction_amount,
                'original_currency': currency,
                'fee_rate': fee_rate,
                'plan_type': plan_type
            }
            
        except Exception as e:
            logger.error(f"Failed to calculate transaction fee: {e}")
            return {
                'fee_amount': Dec('0'),
                'fee_currency': currency,
                'original_amount': transaction_amount,
                'original_currency': currency,
                'fee_rate': Dec('0'),
                'plan_type': 'unknown',
                'error': str(e)
            }
    
    def calculate_revenue_share(self, subscription: Dict[str, Any],
                                  revenue_amount: Decimal,
                                  currency: str = 'USD') -> Dict[str, Any]:
        """
        Calculate revenue share fee based on revenue generated.
        
        Args:
            subscription: Broker subscription dict with fee settings
            revenue_amount: The revenue amount to calculate share on
            currency: Currency of the revenue
            
        Returns:
            Dict with revenue share details:
            {
                'share_amount': Decimal,
                'share_currency': str,
                'original_amount': Decimal,
                'original_currency': str,
                'share_percentage': Decimal,
                'plan_type': str
            }
        """
        try:
            plan_type = subscription.get('plan_type', self.PLAN_FREE)
            
            # Professional and Enterprise plans have 0% revenue share
            if plan_type in [self.PLAN_PROFESSIONAL, self.PLAN_ENTERPRISE]:
                return {
                    'share_amount': Dec('0'),
                    'share_currency': currency,
                    'original_amount': revenue_amount,
                    'original_currency': currency,
                    'share_percentage': Dec('0'),
                    'plan_type': plan_type
                }
            
            # Get revenue share percentage from subscription
            share_percentage = Dec(str(subscription.get('revenue_share_percentage', 0)))
            monthly_fee_currency = subscription.get('monthly_fee_currency', 'USD')
            
            # Convert amount to fee currency if needed
            if currency != monthly_fee_currency:
                from .currency_converter import CurrencyConverter
                converter = CurrencyConverter(self.db_manager)
                revenue_amount = converter.convert(
                    revenue_amount, currency, monthly_fee_currency
                )
            
            # Calculate revenue share
            share_amount = revenue_amount * (share_percentage / Dec('100'))
            
            return {
                'share_amount': share_amount,
                'share_currency': monthly_fee_currency,
                'original_amount': revenue_amount,
                'original_currency': currency,
                'share_percentage': share_percentage,
                'plan_type': plan_type
            }
            
        except Exception as e:
            logger.error(f"Failed to calculate revenue share: {e}")
            return {
                'share_amount': Dec('0'),
                'share_currency': currency,
                'original_amount': revenue_amount,
                'original_currency': currency,
                'share_percentage': Dec('0'),
                'plan_type': 'unknown',
                'error': str(e)
            }
    
    def calculate_monthly_fee(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """
        Get monthly subscription fee for a broker.
        
        Args:
            subscription: Broker subscription dict with fee settings
            
        Returns:
            Dict with monthly fee details:
            {
                'monthly_fee': Decimal,
                'currency': str,
                'plan_type': str,
                'billing_cycle_start': date,
                'billing_cycle_end': date
            }
        """
        try:
            plan_type = subscription.get('plan_type', self.PLAN_FREE)
            monthly_fee = Dec(str(subscription.get('monthly_fee', 0)))
            currency = subscription.get('monthly_fee_currency', 'USD')
            billing_cycle_start = subscription.get('billing_cycle_start')
            billing_cycle_end = subscription.get('billing_cycle_end')
            
            return {
                'monthly_fee': monthly_fee,
                'currency': currency,
                'plan_type': plan_type,
                'billing_cycle_start': billing_cycle_start,
                'billing_cycle_end': billing_cycle_end
            }
            
        except Exception as e:
            logger.error(f"Failed to calculate monthly fee: {e}")
            return {
                'monthly_fee': Dec('0'),
                'currency': 'USD',
                'plan_type': 'unknown',
                'error': str(e)
            }
    
    def calculate_total_fees_for_period(self, user_id: int,
                                          period_start: date,
                                          period_end: date) -> Dict[str, Any]:
        """
        Calculate total fees for a broker for a given period.
        
        Args:
            user_id: Broker user ID
            period_start: Start date of the period
            period_end: End date of the period
            
        Returns:
            Dict with total fee breakdown:
            {
                'total_transaction_fees': Decimal,
                'total_revenue_share': Decimal,
                'monthly_fee': Decimal,
                'total_fees': Decimal,
                'currency': str,
                'period_start': date,
                'period_end': date,
                'transactions_count': int
            }
        """
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerTransactionModel, BrokerSubscriptionModel
                
                # Get subscription
                subscription = session.query(BrokerSubscriptionModel).filter_by(
                    user_id=user_id
                ).first()
                
                if not subscription:
                    return {
                        'total_transaction_fees': Dec('0'),
                        'total_revenue_share': Dec('0'),
                        'monthly_fee': Dec('0'),
                        'total_fees': Dec('0'),
                        'currency': 'USD',
                        'period_start': period_start,
                        'period_end': period_end,
                        'transactions_count': 0,
                        'error': 'Subscription not found'
                    }
                
                # Get transactions for period
                transactions = session.query(BrokerTransactionModel).filter(
                    BrokerTransactionModel.user_id == user_id,
                    BrokerTransactionModel.created_at >= period_start,
                    BrokerTransactionModel.created_at <= period_end,
                    BrokerTransactionModel.status == 'completed'
                ).all()
                
                # Calculate totals
                total_transaction_fees = Dec('0')
                total_revenue_share = Dec('0')
                monthly_fee = Dec('0')
                currency = subscription.monthly_fee_currency or 'USD'
                
                for txn in transactions:
                    amount = Dec(str(txn.amount))
                    if txn.transaction_type == self.TXN_TYPE_TRANSACTION_FEE:
                        total_transaction_fees += amount
                    elif txn.transaction_type == self.TXN_TYPE_REVENUE_SHARE:
                        total_revenue_share += amount
                    elif txn.transaction_type == self.TXN_TYPE_MONTHLY_FEE:
                        monthly_fee += amount
                
                total_fees = total_transaction_fees + total_revenue_share + monthly_fee
                
                return {
                    'total_transaction_fees': total_transaction_fees,
                    'total_revenue_share': total_revenue_share,
                    'monthly_fee': monthly_fee,
                    'total_fees': total_fees,
                    'currency': currency,
                    'period_start': period_start,
                    'period_end': period_end,
                    'transactions_count': len(transactions)
                }
                
            finally:
                session.close()
                
        except Exception as e:
            logger.error(f"Failed to calculate total fees for period: {e}")
            return {
                'total_transaction_fees': Dec('0'),
                'total_revenue_share': Dec('0'),
                'monthly_fee': Dec('0'),
                'total_fees': Dec('0'),
                'currency': 'USD',
                'period_start': period_start,
                'period_end': period_end,
                'transactions_count': 0,
                'error': str(e)
            }
    
    def get_plan_limits(self, plan_type: str) -> Dict[str, Any]:
        """
        Get limits for a subscription plan.
        
        Args:
            plan_type: Plan type (free, basic, professional, enterprise)
            
        Returns:
            Dict with plan limits:
            {
                'max_api_keys': int,
                'allow_custom_gateway': bool,
                'allow_dedicated_session': bool,
                'support_level': str
            }
        """
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import SubscriptionPlanModel
                
                plan = session.query(SubscriptionPlanModel).filter_by(
                    plan_type=plan_type,
                    is_active=True
                ).first()
                
                if plan:
                    return {
                        'max_api_keys': plan.max_api_keys,
                        'allow_custom_gateway': plan.allow_custom_gateway,
                        'allow_dedicated_session': plan.allow_dedicated_session,
                        'support_level': self._get_support_level(plan_type),
                        'features': plan.features or {}
                    }
                
                # Default limits if plan not found
                return self._get_default_limits(plan_type)
                
            finally:
                session.close()
                
        except Exception as e:
            logger.error(f"Failed to get plan limits: {e}")
            return self._get_default_limits(plan_type)
    
    def _get_default_limits(self, plan_type: str) -> Dict[str, Any]:
        """Get default limits for a plan type."""
        defaults = {
            self.PLAN_FREE: {
                'max_api_keys': 1,
                'allow_custom_gateway': False,
                'allow_dedicated_session': False,
                'support_level': 'email'
            },
            self.PLAN_BASIC: {
                'max_api_keys': 5,
                'allow_custom_gateway': False,
                'allow_dedicated_session': False,
                'support_level': 'email_chat'
            },
            self.PLAN_PROFESSIONAL: {
                'max_api_keys': -1,  # Unlimited
                'allow_custom_gateway': True,
                'allow_dedicated_session': False,
                'support_level': 'priority'
            },
            self.PLAN_ENTERPRISE: {
                'max_api_keys': -1,  # Unlimited
                'allow_custom_gateway': True,
                'allow_dedicated_session': True,
                'support_level': 'dedicated'
            }
        }
        return defaults.get(plan_type, defaults[self.PLAN_FREE])
    
    def _get_support_level(self, plan_type: str) -> str:
        """Get support level for a plan type."""
        levels = {
            self.PLAN_FREE: 'email',
            self.PLAN_BASIC: 'email_chat',
            self.PLAN_PROFESSIONAL: 'priority',
            self.PLAN_ENTERPRISE: 'dedicated'
        }
        return levels.get(plan_type, 'email')
    
    def check_api_key_limit(self, subscription: Dict[str, Any], 
                             current_key_count: int) -> Dict[str, Any]:
        """
        Check if broker can create more API keys.
        
        Args:
            subscription: Broker subscription dict
            current_key_count: Current number of API keys
            
        Returns:
            Dict with limit check result:
            {
                'can_create': bool,
                'current_count': int,
                'max_keys': int,
                'remaining': int
            }
        """
        plan_type = subscription.get('plan_type', self.PLAN_FREE)
        limits = self.get_plan_limits(plan_type)
        max_keys = limits.get('max_api_keys', 1)
        
        # -1 means unlimited
        if max_keys == -1:
            return {
                'can_create': True,
                'current_count': current_key_count,
                'max_keys': -1,
                'remaining': -1
            }
        
        return {
            'can_create': current_key_count < max_keys,
            'current_count': current_key_count,
            'max_keys': max_keys,
            'remaining': max(0, max_keys - current_key_count)
        }
    
    def check_custom_gateway_allowed(self, plan_type: str) -> bool:
        """
        Check if custom gateway is allowed for a plan.
        
        Args:
            plan_type: Plan type
            
        Returns:
            True if custom gateway is allowed
        """
        limits = self.get_plan_limits(plan_type)
        return limits.get('allow_custom_gateway', False)