"""
Chart Service for Reports Dashboard
Provides chart data generation and analytics visualization
"""
import json
from django.http import JsonResponse
from django.db.models import Sum, Count, Avg, Q
from django.utils import timezone
from datetime import timedelta, datetime
from decimal import Decimal
from loans.models import Loan, Repayment
from users.models import CustomUser
from .comprehensive_reports import reports_service


class ChartService:
    """
    Service class for generating chart data for reports dashboard
    """
    
    def __init__(self):
        self.today = timezone.now().date()
    
    def get_loan_performance_chart_data(self, branch_id=None, months_limit=12):
        """
        Generate loan performance chart data for monthly disbursements vs collections
        Args:
            branch_id: Optional branch ID to filter data
            months_limit: Number of months to show (default 12)
        """
        try:
            # Get last N months data
            months = []
            disbursements = []
            collections = []
            
            # Ensure months_limit is reasonable
            if not isinstance(months_limit, int) or months_limit < 1:
                months_limit = 12
            elif months_limit > 24:  # Cap at 24 months
                months_limit = 24
            
            for i in range(months_limit - 1, -1, -1):
                month_date = self.today.replace(day=1) - timedelta(days=i*30)
                month_start = month_date.replace(day=1)
                
                if i == 0:
                    month_end = self.today
                else:
                    if month_start.month == 12:
                        next_month = month_start.replace(year=month_start.year + 1, month=1)
                    else:
                        next_month = month_start.replace(month=month_start.month + 1)
                    month_end = next_month - timedelta(days=1)
                
                # Get disbursements for this month
                loans_qs = Loan.objects.filter(
                    disbursement_date__date__gte=month_start,
                    disbursement_date__date__lte=month_end
                )
                
                if branch_id:
                    loans_qs = loans_qs.filter(borrower__branch_id=branch_id)
                
                month_disbursements = loans_qs.aggregate(
                    total=Sum('principal_amount')
                )['total'] or 0
                
                # Get collections for this month
                repayments_qs = Repayment.objects.filter(
                    payment_date__gte=month_start,
                    payment_date__lte=month_end
                )
                
                if branch_id:
                    repayments_qs = repayments_qs.filter(loan__borrower__branch_id=branch_id)
                
                month_collections = repayments_qs.aggregate(
                    total=Sum('amount')
                )['total'] or 0
                
                months.append(month_start.strftime('%b %Y'))
                disbursements.append(float(month_disbursements))
                collections.append(float(month_collections))
            
            return {
                'labels': months,
                'datasets': [
                    {
                        'label': 'Disbursements',
                        'data': disbursements,
                        'borderColor': '#3b82f6',
                        'backgroundColor': 'rgba(59, 130, 246, 0.1)',
                        'borderWidth': 3,
                        'fill': True,
                        'tension': 0.4
                    },
                    {
                        'label': 'Collections',
                        'data': collections,
                        'borderColor': '#10b981',
                        'backgroundColor': 'rgba(16, 185, 129, 0.1)',
                        'borderWidth': 3,
                        'fill': True,
                        'tension': 0.4
                    }
                ]
            }
        except Exception as e:
            # Return empty chart data if there's an error
            return {
                'labels': [],
                'datasets': [],
                'error': str(e)
            }
    
    def get_portfolio_distribution_chart_data(self, branch_id=None):
        """
        Generate portfolio distribution chart data by loan product
        """
        try:
            # Exclude soft-deleted and rolled-over loans
            loans_qs = Loan.objects.filter(
                status='active',
                is_deleted=False,
                is_rolled_over=False
            ).exclude(status='rolled_over')
            
            if branch_id:
                loans_qs = loans_qs.filter(borrower__branch_id=branch_id)
            
            # Group by loan product
            product_data = loans_qs.values(
                'application__loan_product__name'
            ).annotate(
                total_amount=Sum('principal_amount'),
                loan_count=Count('id')
            ).order_by('-total_amount')
            
            labels = []
            amounts = []
            colors = [
                '#3b82f6', '#ef4444', '#10b981', '#f59e0b',
                '#8b5cf6', '#06b6d4', '#84cc16', '#f97316'
            ]
            
            for i, item in enumerate(product_data):
                product_name = item['application__loan_product__name'] or 'Unknown Product'
                labels.append(product_name)
                amounts.append(float(item['total_amount']))
            
            return {
                'labels': labels,
                'datasets': [{
                    'data': amounts,
                    'backgroundColor': colors[:len(labels)],
                    'borderWidth': 2,
                    'borderColor': '#fff'
                }]
            }
        except Exception as e:
            return {
                'labels': [],
                'datasets': [],
                'error': str(e)
            }
    
    def get_collection_rate_chart_data(self, branch_id=None):
        """
        Generate collection rate chart data over time
        """
        try:
            months = []
            collection_rates = []
            
            for i in range(5, -1, -1):
                month_date = self.today.replace(day=1) - timedelta(days=i*30)
                month_start = month_date.replace(day=1)
                
                if i == 0:
                    month_end = self.today
                else:
                    next_month = month_start.replace(month=month_start.month + 1) if month_start.month < 12 else month_start.replace(year=month_start.year + 1, month=1)
                    month_end = next_month - timedelta(days=1)
                
                # Get loans due in this month
                loans_due_qs = Loan.objects.filter(
                    due_date__date__gte=month_start,
                    due_date__date__lte=month_end
                )
                
                if branch_id:
                    loans_due_qs = loans_due_qs.filter(borrower__branch_id=branch_id)
                
                total_due = loans_due_qs.aggregate(
                    total=Sum('total_amount')
                )['total'] or 0
                
                # Get collections for this month
                collections_qs = Repayment.objects.filter(
                    payment_date__gte=month_start,
                    payment_date__lte=month_end
                )
                
                if branch_id:
                    collections_qs = collections_qs.filter(loan__borrower__branch_id=branch_id)
                
                total_collected = collections_qs.aggregate(
                    total=Sum('amount')
                )['total'] or 0
                
                # Calculate collection rate
                collection_rate = (total_collected / total_due * 100) if total_due > 0 else 0
                
                months.append(month_start.strftime('%b %Y'))
                collection_rates.append(float(collection_rate))
            
            return {
                'labels': months,
                'datasets': [{
                    'label': 'Collection Rate (%)',
                    'data': collection_rates,
                    'borderColor': '#10b981',
                    'backgroundColor': 'rgba(16, 185, 129, 0.1)',
                    'borderWidth': 3,
                    'fill': True,
                    'tension': 0.4
                }]
            }
        except Exception as e:
            return {
                'labels': [],
                'datasets': [],
                'error': str(e)
            }
    
    def get_delinquency_trend_chart_data(self, branch_id=None, months_limit=6):
        """
        Generate delinquency trend chart data
        Args:
            branch_id: Optional branch ID to filter data
            months_limit: Number of months to show (default 6)
        """
        try:
            months = []
            delinquent_counts = []
            delinquent_amounts = []
            
            # Ensure months_limit is reasonable
            if not isinstance(months_limit, int) or months_limit < 1:
                months_limit = 6
            elif months_limit > 12:  # Cap at 12 months for delinquency
                months_limit = 12
            
            for i in range(months_limit - 1, -1, -1):
                month_date = self.today.replace(day=1) - timedelta(days=i*30)
                month_start = month_date.replace(day=1)
                
                if i == 0:
                    month_end = self.today
                else:
                    if month_start.month == 12:
                        next_month = month_start.replace(year=month_start.year + 1, month=1)
                    else:
                        next_month = month_start.replace(month=month_start.month + 1)
                    month_end = next_month - timedelta(days=1)
                
                # Get delinquent loans for this month
                delinquent_qs = Loan.objects.filter(
                    status='active',
                    due_date__lt=month_end
                ).select_related('borrower')  # Optimize query
                
                if branch_id:
                    delinquent_qs = delinquent_qs.filter(borrower__branch_id=branch_id)
                
                delinquent_count = delinquent_qs.count()
                
                # Calculate total delinquent amount using aggregation
                delinquent_amount = delinquent_qs.annotate(
                    outstanding=F('total_amount') - Coalesce(F('amount_paid'), 0)
                ).filter(outstanding__gt=0).aggregate(
                    total=Sum('outstanding')
                )['total'] or 0
                
                months.append(month_start.strftime('%b %Y'))
                delinquent_counts.append(delinquent_count)
                delinquent_amounts.append(float(delinquent_amount))
            
            return {
                'labels': months,
                'datasets': [
                    {
                        'label': 'Delinquent Count',
                        'data': delinquent_counts,
                        'borderColor': '#ef4444',
                        'backgroundColor': 'rgba(239, 68, 68, 0.1)',
                        'borderWidth': 3,
                        'fill': False,
                        'yAxisID': 'y'
                    },
                    {
                        'label': 'Delinquent Amount',
                        'data': delinquent_amounts,
                        'borderColor': '#f59e0b',
                        'backgroundColor': 'rgba(245, 158, 11, 0.1)',
                        'borderWidth': 3,
                        'fill': False,
                        'yAxisID': 'y1'
                    }
                ]
            }
        except Exception as e:
            return {
                'labels': [],
                'datasets': [],
                'error': str(e)
            }
    
    def get_revenue_breakdown_chart_data(self, branch_id=None):
        """
        Generate revenue breakdown chart data (processing fees, interest, etc.)
        """
        try:
            # Get current month data
            current_month_start = self.today.replace(day=1)
            
            loans_qs = Loan.objects.filter(
                created_at__date__gte=current_month_start
            )
            
            if branch_id:
                loans_qs = loans_qs.filter(borrower__branch_id=branch_id)
            
            # Calculate revenue components
            processing_fees = loans_qs.aggregate(
                total=Sum('processing_fee')
            )['total'] or 0
            
            interest_income = loans_qs.aggregate(
                total=Sum('interest_amount')
            )['total'] or 0
            
            # Get registration fees (simplified)
            registration_fees = CustomUser.objects.filter(
                role='borrower',
                registration_fee_paid=True,
                created_at__date__gte=current_month_start
            )
            
            if branch_id:
                registration_fees = registration_fees.filter(branch_id=branch_id)
            
            registration_income = registration_fees.aggregate(
                total=Sum('registration_fee_amount')
            )['total'] or 0
            
            return {
                'labels': ['Processing Fees', 'Interest Income', 'Registration Fees'],
                'datasets': [{
                    'data': [
                        float(processing_fees),
                        float(interest_income),
                        float(registration_income)
                    ],
                    'backgroundColor': ['#3b82f6', '#10b981', '#f59e0b'],
                    'borderWidth': 2,
                    'borderColor': '#fff'
                }]
            }
        except Exception as e:
            return {
                'labels': [],
                'datasets': [],
                'error': str(e)
            }


# Service instance
chart_service = ChartService()