"""
Billing API endpoints for broker subscription management
"""

import logging
from datetime import datetime, timedelta
from typing import Dict, Any, Optional
from flask import request, jsonify, g

from ..database.manager import DatabaseManager
from ..billing.billing_engine import BillingEngine
from ..billing.subscription_manager import SubscriptionManager
from ..billing.fee_calculator import FeeCalculator
from ..billing.currency_converter import CurrencyConverter

logger = logging.getLogger(__name__)


class BillingAPI:
    """REST API endpoints for billing and subscription management"""
    
    def __init__(self, db_manager: DatabaseManager, billing_engine: BillingEngine):
        self.db_manager = db_manager
        self.billing_engine = billing_engine
        self.subscription_manager = SubscriptionManager(db_manager)
        self.fee_calculator = FeeCalculator(db_manager)
        self.currency_converter = CurrencyConverter(db_manager)
        
        logger.info("BillingAPI initialized")
    
    # ==================== Subscription Management ====================
    
    def get_subscription(self, user_id: int) -> Dict[str, Any]:
        """Get subscription details for a user"""
        try:
            subscription = self.subscription_manager.get_subscription(user_id)
            if subscription:
                return {
                    'success': True,
                    'subscription': subscription.to_dict()
                }
            else:
                return {
                    'success': True,
                    'subscription': None,
                    'message': 'No subscription found'
                }
        except Exception as e:
            logger.error(f"Failed to get subscription: {e}")
            return {'error': str(e)}
    
    def create_subscription(self, user_id: int, plan_type: str, 
                           currency: str = 'USD', timezone: str = 'UTC',
                           is_trial: bool = False) -> Dict[str, Any]:
        """Create new subscription for user"""
        try:
            subscription = self.subscription_manager.create_subscription(
                user_id=user_id,
                plan_type=plan_type,
                currency=currency,
                timezone=timezone,
                is_trial=is_trial
            )
            
            if subscription:
                return {
                    'success': True,
                    'subscription': subscription.to_dict(),
                    'message': f'Subscription created successfully'
                }
            else:
                return {'error': 'Failed to create subscription'}
        except Exception as e:
            logger.error(f"Failed to create subscription: {e}")
            return {'error': str(e)}
    
    def update_subscription(self, user_id: int, **kwargs) -> Dict[str, Any]:
        """Update subscription details"""
        try:
            subscription = self.subscription_manager.update_subscription(user_id, **kwargs)
            if subscription:
                return {
                    'success': True,
                    'subscription': subscription.to_dict(),
                    'message': 'Subscription updated successfully'
                }
            else:
                return {'error': 'Failed to update subscription'}
        except Exception as e:
            logger.error(f"Failed to update subscription: {e}")
            return {'error': str(e)}
    
    def upgrade_subscription(self, user_id: int, new_plan_type: str) -> Dict[str, Any]:
        """Upgrade subscription to a higher plan"""
        try:
            result = self.subscription_manager.upgrade_subscription(user_id, new_plan_type)
            return {
                'success': True,
                'subscription': result.to_dict(),
                'message': f'Subscription upgraded to {new_plan_type}'
            }
        except Exception as e:
            logger.error(f"Failed to upgrade subscription: {e}")
            return {'error': str(e)}
    
    def downgrade_subscription(self, user_id: int, new_plan_type: str) -> Dict[str, Any]:
        """Downgrade subscription to a lower plan"""
        try:
            result = self.subscription_manager.downgrade_subscription(user_id, new_plan_type)
            return {
                'success': True,
                'subscription': result.to_dict(),
                'message': f'Subscription downgraded to {new_plan_type}'
            }
        except Exception as e:
            logger.error(f"Failed to downgrade subscription: {e}")
            return {'error': str(e)}
    
    def cancel_subscription(self, user_id: int, immediate: bool = False) -> Dict[str, Any]:
        """Cancel subscription"""
        try:
            subscription = self.subscription_manager.cancel_subscription(user_id, immediate)
            if subscription:
                return {
                    'success': True,
                    'subscription': subscription.to_dict(),
                    'message': 'Subscription cancelled successfully'
                }
            else:
                return {'error': 'Failed to cancel subscription'}
        except Exception as e:
            logger.error(f"Failed to cancel subscription: {e}")
            return {'error': str(e)}
    
    def get_subscription_plans(self) -> Dict[str, Any]:
        """Get all available subscription plans"""
        try:
            plans = self.subscription_manager.get_all_plans()
            return {
                'success': True,
                'plans': [plan.to_dict() for plan in plans]
            }
        except Exception as e:
            logger.error(f"Failed to get subscription plans: {e}")
            return {'error': str(e)}
    
    # ==================== Fee Calculation ====================
    
    def calculate_transaction_fee(self, user_id: int, bet_amount: float, 
                                  currency: str = 'USD') -> Dict[str, Any]:
        """Calculate transaction fee for a bet"""
        try:
            fee_result = self.fee_calculator.calculate_fee(user_id, bet_amount, currency)
            return {
                'success': True,
                'fee_calculation': fee_result
            }
        except Exception as e:
            logger.error(f"Failed to calculate transaction fee: {e}")
            return {'error': str(e)}
    
    def calculate_revenue_share(self, user_id: int, total_revenue: float,
                                currency: str = 'USD') -> Dict[str, Any]:
        """Calculate revenue share for a broker"""
        try:
            share_result = self.fee_calculator.calculate_revenue_share(user_id, total_revenue, currency)
            return {
                'success': True,
                'revenue_share': share_result
            }
        except Exception as e:
            logger.error(f"Failed to calculate revenue share: {e}")
            return {'error': str(e)}
    
    # ==================== Currency Management ====================
    
    def get_currencies(self, currency_type: str = None) -> Dict[str, Any]:
        """Get all supported currencies"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import CurrencyModel
                
                query = session.query(CurrencyModel).filter_by(is_active=True)
                if currency_type:
                    query = query.filter_by(currency_type=currency_type)
                
                currencies = query.all()
                return {
                    'success': True,
                    'currencies': [c.to_dict() for c in currencies]
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get currencies: {e}")
            return {'error': str(e)}
    
    def convert_currency(self, amount: float, from_currency: str, 
                        to_currency: str) -> Dict[str, Any]:
        """Convert amount from one currency to another"""
        try:
            result = self.currency_converter.convert(amount, from_currency, to_currency)
            return {
                'success': True,
                'conversion': result
            }
        except Exception as e:
            logger.error(f"Failed to convert currency: {e}")
            return {'error': str(e)}
    
    def get_exchange_rate(self, from_currency: str, to_currency: str) -> Dict[str, Any]:
        """Get current exchange rate"""
        try:
            rate = self.currency_converter.get_rate(from_currency, to_currency)
            return {
                'success': True,
                'from_currency': from_currency,
                'to_currency': to_currency,
                'rate': rate
            }
        except Exception as e:
            logger.error(f"Failed to get exchange rate: {e}")
            return {'error': str(e)}
    
    # ==================== Invoice Management ====================
    
    def get_invoices(self, user_id: int, status: str = None, 
                    limit: int = 20, offset: int = 0) -> Dict[str, Any]:
        """Get invoices for a user"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerInvoiceModel
                
                query = session.query(BrokerInvoiceModel).filter_by(user_id=user_id)
                if status:
                    query = query.filter_by(status=status)
                
                total = query.count()
                invoices = query.order_by(BrokerInvoiceModel.created_at.desc()).offset(offset).limit(limit).all()
                
                return {
                    'success': True,
                    'invoices': [inv.to_dict() for inv in invoices],
                    'total': total,
                    'limit': limit,
                    'offset': offset
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get invoices: {e}")
            return {'error': str(e)}
    
    def get_invoice(self, invoice_id: int) -> Dict[str, Any]:
        """Get specific invoice details"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerInvoiceModel
                
                invoice = session.query(BrokerInvoiceModel).filter_by(id=invoice_id).first()
                if invoice:
                    return {
                        'success': True,
                        'invoice': invoice.to_dict()
                    }
                else:
                    return {'error': 'Invoice not found'}
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get invoice: {e}")
            return {'error': str(e)}
    
    def generate_invoice(self, user_id: int, billing_period_start: str,
                        billing_period_end: str) -> Dict[str, Any]:
        """Generate invoice for billing period"""
        try:
            invoice = self.billing_engine.generate_invoice(user_id, billing_period_start, billing_period_end)
            if invoice:
                return {
                    'success': True,
                    'invoice': invoice.to_dict(),
                    'message': 'Invoice generated successfully'
                }
            else:
                return {'error': 'Failed to generate invoice'}
        except Exception as e:
            logger.error(f"Failed to generate invoice: {e}")
            return {'error': str(e)}
    
    # ==================== Transaction History ====================
    
    def get_transactions(self, user_id: int, transaction_type: str = None,
                        status: str = None, limit: int = 50, 
                        offset: int = 0) -> Dict[str, Any]:
        """Get transaction history for a user"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerTransactionModel
                
                query = session.query(BrokerTransactionModel).filter_by(user_id=user_id)
                if transaction_type:
                    query = query.filter_by(transaction_type=transaction_type)
                if status:
                    query = query.filter_by(status=status)
                
                total = query.count()
                transactions = query.order_by(BrokerTransactionModel.created_at.desc()).offset(offset).limit(limit).all()
                
                return {
                    'success': True,
                    'transactions': [tx.to_dict() for tx in transactions],
                    'total': total,
                    'limit': limit,
                    'offset': offset
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get transactions: {e}")
            return {'error': str(e)}
    
    # ==================== Usage Statistics ====================
    
    def get_usage_stats(self, user_id: int, period_start: str = None,
                       period_end: str = None) -> Dict[str, Any]:
        """Get usage statistics for a user"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerUsageStatsModel
                from datetime import datetime
                
                query = session.query(BrokerUsageStatsModel).filter_by(user_id=user_id)
                
                if period_start:
                    query = query.filter(BrokerUsageStatsModel.period_start >= datetime.fromisoformat(period_start))
                if period_end:
                    query = query.filter(BrokerUsageStatsModel.period_end <= datetime.fromisoformat(period_end))
                
                stats = query.order_by(BrokerUsageStatsModel.period_start.desc()).all()
                
                return {
                    'success': True,
                    'usage_stats': [s.to_dict() for s in stats]
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get usage stats: {e}")
            return {'error': str(e)}
    
    def get_current_usage(self, user_id: int) -> Dict[str, Any]:
        """Get current billing period usage"""
        try:
            usage = self.billing_engine.get_current_usage(user_id)
            return {
                'success': True,
                'current_usage': usage
            }
        except Exception as e:
            logger.error(f"Failed to get current usage: {e}")
            return {'error': str(e)}
    
    # ==================== Payment Gateway Management ====================
    
    def get_payment_gateways(self, gateway_type: str = None) -> Dict[str, Any]:
        """Get available payment gateways"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import PaymentGatewayModel
                
                query = session.query(PaymentGatewayModel).filter_by(is_active=True)
                if gateway_type:
                    query = query.filter_by(gateway_type=gateway_type)
                
                gateways = query.all()
                
                # Don't expose sensitive data
                safe_gateways = []
                for gw in gateways:
                    gw_dict = gw.to_dict(exclude_fields=['api_key', 'api_secret', 'webhook_secret'])
                    safe_gateways.append(gw_dict)
                
                return {
                    'success': True,
                    'gateways': safe_gateways
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get payment gateways: {e}")
            return {'error': str(e)}
    
    # ==================== Admin Endpoints ====================
    
    def get_all_subscriptions(self, status: str = None, plan_type: str = None,
                             limit: int = 50, offset: int = 0) -> Dict[str, Any]:
        """Get all subscriptions (admin only)"""
        try:
            session = self.db_manager.get_session()
            try:
                from ..database.models import BrokerSubscriptionModel
                
                query = session.query(BrokerSubscriptionModel)
                if status:
                    query = query.filter_by(status=status)
                if plan_type:
                    query = query.filter_by(plan_type=plan_type)
                
                total = query.count()
                subscriptions = query.order_by(BrokerSubscriptionModel.created_at.desc()).offset(offset).limit(limit).all()
                
                return {
                    'success': True,
                    'subscriptions': [s.to_dict() for s in subscriptions],
                    'total': total,
                    'limit': limit,
                    'offset': offset
                }
            finally:
                session.close()
        except Exception as e:
            logger.error(f"Failed to get all subscriptions: {e}")
            return {'error': str(e)}
    
    def get_billing_summary(self) -> Dict[str, Any]:
        """Get billing summary statistics (admin only)"""
        try:
            summary = self.billing_engine.get_billing_summary()
            return {
                'success': True,
                'summary': summary
            }
        except Exception as e:
            logger.error(f"Failed to get billing summary: {e}")
            return {'error': str(e)}
    
    def update_exchange_rates(self) -> Dict[str, Any]:
        """Manually trigger exchange rate update (admin only)"""
        try:
            from ..billing.exchange_rate_updater import ExchangeRateUpdater
            updater = ExchangeRateUpdater(self.db_manager)
            result = updater.update_all_rates()
            return {
                'success': True,
                'update_result': result,
                'message': 'Exchange rates updated'
            }
        except Exception as e:
            logger.error(f"Failed to update exchange rates: {e}")
            return {'error': str(e)}


def init_billing_routes(app, billing_api: BillingAPI, auth_manager):
    """Initialize billing API routes for Flask app"""
    from .auth import require_api_auth
    
    @app.route('/api/billing/subscription', methods=['GET'])
    @require_api_auth
    def get_my_subscription():
        """Get current user's subscription"""
        user_id = request.current_user.get('user_id')
        return jsonify(billing_api.get_subscription(user_id))
    
    @app.route('/api/billing/subscription', methods=['POST'])
    @require_api_auth
    def create_my_subscription():
        """Create subscription for current user"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.create_subscription(
            user_id=user_id,
            plan_type=data.get('plan_type', 'free'),
            currency=data.get('currency', 'USD'),
            timezone=data.get('timezone', 'UTC'),
            is_trial=data.get('is_trial', False)
        ))
    
    @app.route('/api/billing/subscription', methods=['PUT'])
    @require_api_auth
    def update_my_subscription():
        """Update current user's subscription"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.update_subscription(user_id, **data))
    
    @app.route('/api/billing/subscription/upgrade', methods=['POST'])
    @require_api_auth
    def upgrade_my_subscription():
        """Upgrade current user's subscription"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.upgrade_subscription(
            user_id=user_id,
            new_plan_type=data.get('plan_type')
        ))
    
    @app.route('/api/billing/subscription/downgrade', methods=['POST'])
    @require_api_auth
    def downgrade_my_subscription():
        """Downgrade current user's subscription"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.downgrade_subscription(
            user_id=user_id,
            new_plan_type=data.get('plan_type')
        ))
    
    @app.route('/api/billing/subscription/cancel', methods=['POST'])
    @require_api_auth
    def cancel_my_subscription():
        """Cancel current user's subscription"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.cancel_subscription(
            user_id=user_id,
            immediate=data.get('immediate', False)
        ))
    
    @app.route('/api/billing/plans', methods=['GET'])
    def get_subscription_plans():
        """Get all available subscription plans"""
        return jsonify(billing_api.get_subscription_plans())
    
    @app.route('/api/billing/plans/<int:plan_id>', methods=['GET'])
    def get_subscription_plan(plan_id):
        """Get a single subscription plan by ID"""
        from ..database.models import SubscriptionPlanModel
        session = None
        try:
            session = db_manager.get_session()
            plan = session.query(SubscriptionPlanModel).filter_by(id=plan_id).first()
            if plan:
                return jsonify({'success': True, 'plan': plan.to_dict()})
            else:
                return jsonify({'success': False, 'error': 'Plan not found'}), 404
        except Exception as e:
            logger.error(f"Error getting plan: {e}")
            return jsonify({'success': False, 'error': str(e)}), 500
        finally:
            if session:
                session.close()
    
    @app.route('/api/billing/plans/<int:plan_id>', methods=['PUT'])
    def update_subscription_plan(plan_id):
        """Update a subscription plan"""
        session = None
        try:
            data = request.get_json() or {}
            session = db_manager.get_session()
            plan = session.query(SubscriptionPlanModel).filter_by(id=plan_id).first()
            if not plan:
                return jsonify({'success': False, 'error': 'Plan not found'}), 404
            
            # Update fields
            if 'display_name' in data:
                plan.display_name = data['display_name']
            if 'description' in data:
                plan.description = data['description']
            if 'monthly_fee' in data:
                plan.monthly_fee = float(data['monthly_fee'])
            if 'transaction_fee' in data:
                plan.transaction_fee = float(data['transaction_fee'])
            if 'revenue_share_percentage' in data:
                plan.revenue_share_percentage = float(data['revenue_share_percentage'])
            if 'max_api_keys' in data:
                plan.max_api_keys = int(data['max_api_keys'])
            if 'api_requests_per_month' in data:
                plan.api_requests_per_month = int(data['api_requests_per_month'])
            if 'allow_custom_gateway' in data:
                plan.allow_custom_gateway = bool(data['allow_custom_gateway'])
            if 'allow_dedicated_session' in data:
                plan.allow_dedicated_session = bool(data['allow_dedicated_session'])
            if 'support_level' in data:
                plan.support_level = data['support_level']
            if 'is_active' in data:
                plan.is_active = bool(data['is_active'])
            if 'is_featured' in data:
                plan.is_featured = bool(data['is_featured'])
            if 'contact_for_pricing' in data:
                plan.contact_for_pricing = bool(data['contact_for_pricing'])
            
            plan.updated_at = datetime.utcnow()
            session.commit()
            
            return jsonify({'success': True, 'plan': plan.to_dict()})
        except Exception as e:
            logger.error(f"Error updating plan: {e}")
            if session:
                session.rollback()
            return jsonify({'success': False, 'error': str(e)}), 500
        finally:
            if session:
                session.close()
    
    @app.route('/api/billing/fee/calculate', methods=['POST'])
    @require_api_auth
    def calculate_fee():
        """Calculate transaction fee"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.calculate_transaction_fee(
            user_id=user_id,
            bet_amount=data.get('bet_amount', 0),
            currency=data.get('currency', 'USD')
        ))
    
    @app.route('/api/billing/revenue-share/calculate', methods=['POST'])
    @require_api_auth
    def calculate_revenue_share():
        """Calculate revenue share"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.calculate_revenue_share(
            user_id=user_id,
            total_revenue=data.get('total_revenue', 0),
            currency=data.get('currency', 'USD')
        ))
    
    @app.route('/api/billing/currencies', methods=['GET'])
    def get_currencies():
        """Get all supported currencies"""
        currency_type = request.args.get('type')
        return jsonify(billing_api.get_currencies(currency_type))
    
    @app.route('/api/billing/currency/convert', methods=['POST'])
    def convert_currency():
        """Convert currency"""
        data = request.get_json() or {}
        
        return jsonify(billing_api.convert_currency(
            amount=data.get('amount', 0),
            from_currency=data.get('from_currency', 'USD'),
            to_currency=data.get('to_currency', 'USD')
        ))
    
    @app.route('/api/billing/currency/rate', methods=['GET'])
    def get_exchange_rate():
        """Get exchange rate"""
        from_currency = request.args.get('from', 'USD')
        to_currency = request.args.get('to', 'USD')
        
        return jsonify(billing_api.get_exchange_rate(from_currency, to_currency))
    
    @app.route('/api/billing/invoices', methods=['GET'])
    @require_api_auth
    def get_my_invoices():
        """Get current user's invoices"""
        user_id = request.current_user.get('user_id')
        status = request.args.get('status')
        limit = int(request.args.get('limit', 20))
        offset = int(request.args.get('offset', 0))
        
        return jsonify(billing_api.get_invoices(user_id, status, limit, offset))
    
    @app.route('/api/billing/invoices/<int:invoice_id>', methods=['GET'])
    @require_api_auth
    def get_invoice(invoice_id):
        """Get specific invoice"""
        return jsonify(billing_api.get_invoice(invoice_id))
    
    @app.route('/api/billing/invoices/generate', methods=['POST'])
    @require_api_auth
    def generate_my_invoice():
        """Generate invoice for billing period"""
        user_id = request.current_user.get('user_id')
        data = request.get_json() or {}
        
        return jsonify(billing_api.generate_invoice(
            user_id=user_id,
            billing_period_start=data.get('billing_period_start'),
            billing_period_end=data.get('billing_period_end')
        ))
    
    @app.route('/api/billing/transactions', methods=['GET'])
    @require_api_auth
    def get_my_transactions():
        """Get current user's transactions"""
        user_id = request.current_user.get('user_id')
        transaction_type = request.args.get('type')
        status = request.args.get('status')
        limit = int(request.args.get('limit', 50))
        offset = int(request.args.get('offset', 0))
        
        return jsonify(billing_api.get_transactions(user_id, transaction_type, status, limit, offset))
    
    @app.route('/api/billing/usage', methods=['GET'])
    @require_api_auth
    def get_my_usage():
        """Get current user's usage statistics"""
        user_id = request.current_user.get('user_id')
        period_start = request.args.get('period_start')
        period_end = request.args.get('period_end')
        
        return jsonify(billing_api.get_usage_stats(user_id, period_start, period_end))
    
    @app.route('/api/billing/usage/current', methods=['GET'])
    @require_api_auth
    def get_my_current_usage():
        """Get current user's current billing period usage"""
        user_id = request.current_user.get('user_id')
        return jsonify(billing_api.get_current_usage(user_id))
    
    @app.route('/api/billing/gateways', methods=['GET'])
    def get_payment_gateways():
        """Get available payment gateways"""
        gateway_type = request.args.get('type')
        return jsonify(billing_api.get_payment_gateways(gateway_type))
    
    # Admin routes
    @app.route('/api/admin/billing/subscriptions', methods=['GET'])
    @require_api_auth
    def admin_get_subscriptions():
        """Get all subscriptions (admin only)"""
        if not request.current_user.get('is_admin'):
            return jsonify({'error': 'Admin access required'}), 403
        
        status = request.args.get('status')
        plan_type = request.args.get('plan_type')
        limit = int(request.args.get('limit', 50))
        offset = int(request.args.get('offset', 0))
        
        return jsonify(billing_api.get_all_subscriptions(status, plan_type, limit, offset))
    
    @app.route('/api/admin/billing/summary', methods=['GET'])
    @require_api_auth
    def admin_get_billing_summary():
        """Get billing summary (admin only)"""
        if not request.current_user.get('is_admin'):
            return jsonify({'error': 'Admin access required'}), 403
        
        return jsonify(billing_api.get_billing_summary())
    
    @app.route('/api/admin/billing/exchange-rates/update', methods=['POST'])
    @require_api_auth
    def admin_update_exchange_rates():
        """Update exchange rates (admin only)"""
        if not request.current_user.get('is_admin'):
            return jsonify({'error': 'Admin access required'}), 403
        
        return jsonify(billing_api.update_exchange_rates())
    
    logger.info("Billing API routes initialized")