"""
AJAX Views for Real-time Date Filtering and Chart Updates
Provides API endpoints for filtered data retrieval and chart updates
"""
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views import View
from django.utils import timezone
from datetime import datetime, timedelta
import json
import logging

from .comprehensive_reports import ComprehensiveReportsService
from .chart_generation_service import ChartGenerationService

logger = logging.getLogger(__name__)


@method_decorator([login_required, csrf_exempt], name='dispatch')
class FilteredDataAPIView(View):
    """
    API endpoint for retrieving filtered report data with chart configurations
    """
    
    def __init__(self):
        super().__init__()
        self.reports_service = ComprehensiveReportsService()
        self.chart_service = ChartGenerationService()
    
    def get(self, request):
        """
        Handle GET requests for filtered data
        """
        try:
            # Parse request parameters
            start_date = request.GET.get('start_date')
            end_date = request.GET.get('end_date')
            report_type = request.GET.get('report_type', 'dashboard')
            include_comparison = request.GET.get('include_comparison', 'false').lower() == 'true'
            chart_theme = request.GET.get('theme', 'light')
            
            # Validate dates
            if not start_date or not end_date:
                return JsonResponse({
                    'error': 'Both start_date and end_date are required'
                }, status=400)
            
            try:
                start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
                end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
            except ValueError:
                return JsonResponse({
                    'error': 'Invalid date format. Use YYYY-MM-DD'
                }, status=400)
            
            # Validate date range
            if start_date > end_date:
                return JsonResponse({
                    'error': 'Start date cannot be after end date'
                }, status=400)
            
            # Check if date range is too large (more than 2 years)
            days_diff = (end_date - start_date).days
            if days_diff > 730:
                return JsonResponse({
                    'error': 'Date range cannot exceed 2 years'
                }, status=400)
            
            # Get filtered data based on report type
            data = self.get_filtered_report_data(report_type, start_date, end_date, include_comparison)
            
            # Generate chart configurations with theme
            charts = self.generate_chart_configs(report_type, data, chart_theme)
            
            # Prepare response
            response_data = {
                'success': True,
                'data': data,
                'charts': charts,
                'summary': self.generate_summary_data(data),
                'date_range': {
                    'start': start_date.isoformat(),
                    'end': end_date.isoformat(),
                    'days': days_diff
                },
                'metadata': {
                    'report_type': report_type,
                    'theme': chart_theme,
                    'generated_at': timezone.now().isoformat(),
                    'user': request.user.username if request.user.is_authenticated else 'anonymous'
                }
            }
            
            if include_comparison:
                comparison_data = self.get_comparison_data(report_type, start_date, end_date)
                response_data['comparison'] = comparison_data
            
            return JsonResponse(response_data)
            
        except Exception as e:
            logger.error(f"Error in FilteredDataAPIView: {str(e)}")
            return JsonResponse({
                'error': 'Internal server error',
                'message': str(e)
            }, status=500)
    
    def get_filtered_report_data(self, report_type, start_date, end_date, include_comparison=False):
        """
        Get filtered data for specific report type
        """
        date_filter = {'start_date': start_date, 'end_date': end_date}
        
        if report_type == 'loans_due':
            return self.reports_service.get_loans_due_report(
                start_date=start_date,
                end_date=end_date
            )
        elif report_type == 'delinquent_loans':
            return self.reports_service.get_delinquent_loans_report(
                date_filter=date_filter
            )
        elif report_type == 'loans_in_arrears':
            return self.reports_service.get_loans_in_arrears_report(
                date_filter=date_filter
            )
        elif report_type == 'processing_fees':
            return self.reports_service.get_processing_fees_report(
                period='custom',
                custom_dates=date_filter
            )
        elif report_type == 'interest_income':
            return self.reports_service.get_interest_income_report(
                start_date=start_date,
                end_date=end_date
            )
        elif report_type == 'registration_fees':
            return self.reports_service.get_registration_fees_report(
                filters=date_filter
            )
        else:
            # Dashboard - get summary of all reports
            return self.get_dashboard_data(start_date, end_date)
    
    def get_dashboard_data(self, start_date, end_date):
        """
        Get comprehensive dashboard data for date range
        """
        return {
            'loans_due': self.reports_service.get_loans_due_report(start_date, end_date),
            'delinquent': self.reports_service.get_delinquent_loans_report({'start_date': start_date, 'end_date': end_date}),
            'processing_fees': self.reports_service.get_processing_fees_report('custom', {'start_date': start_date, 'end_date': end_date}),
            'interest_income': self.reports_service.get_interest_income_report(start_date, end_date)
        }
    
    def get_comparison_data(self, report_type, start_date, end_date):
        """
        Get comparison data for previous period
        """
        # Calculate previous period dates
        period_length = (end_date - start_date).days
        prev_end_date = start_date - timedelta(days=1)
        prev_start_date = prev_end_date - timedelta(days=period_length)
        
        # Get data for previous period
        prev_data = self.get_filtered_report_data(report_type, prev_start_date, prev_end_date)
        
        return {
            'previous_period': prev_data,
            'period_dates': {
                'start': prev_start_date.isoformat(),
                'end': prev_end_date.isoformat()
            }
        }
    
    def generate_chart_configs(self, report_type, data, theme='light'):
        """
        Generate Chart.js configurations for the report data with theme support
        """
        charts = {}
        
        try:
            if report_type == 'loans_due':
                charts.update(self.generate_loans_due_charts(data, theme))
            elif report_type == 'delinquent_loans':
                charts.update(self.generate_delinquent_charts(data, theme))
            elif report_type == 'loans_in_arrears':
                charts.update(self.generate_arrears_charts(data, theme))
            elif report_type == 'processing_fees':
                charts.update(self.generate_processing_fees_charts(data, theme))
            elif report_type == 'interest_income':
                charts.update(self.generate_interest_charts(data, theme))
            elif report_type == 'registration_fees':
                charts.update(self.generate_registration_charts(data, theme))
            else:
                charts.update(self.generate_dashboard_charts(data, theme))
        except Exception as e:
            logger.error(f"Error generating chart configs: {str(e)}")
            charts['error'] = {'error': str(e)}
        
        return charts
    
    def get_theme_colors(self, theme='light'):
        """Get color scheme based on theme"""
        themes = {
            'light': {
                'primary': '#4e73df',
                'success': '#1cc88a',
                'warning': '#f6c23e',
                'danger': '#e74a3b',
                'info': '#36b9cc',
                'secondary': '#858796',
                'background': '#ffffff',
                'text': '#5a5c69',
                'grid': 'rgba(0,0,0,0.1)'
            },
            'dark': {
                'primary': '#5a6acf',
                'success': '#28a745',
                'warning': '#ffc107',
                'danger': '#dc3545',
                'info': '#17a2b8',
                'secondary': '#6c757d',
                'background': '#2c3e50',
                'text': '#ffffff',
                'grid': 'rgba(255,255,255,0.1)'
            }
        }
        return themes.get(theme, themes['light'])
    
    def generate_loans_due_charts(self, data, theme='light'):
        """Generate chart configs for loans due report"""
        charts = {}
        colors = self.get_theme_colors(theme)
        
        summary = data.get('summary', {})
        
        # Due amounts by urgency
        charts['due_amounts_urgency'] = {
            'type': 'bar',
            'title': 'Loan Amounts Due by Urgency',
            'labels': ['Due Today', 'Due Tomorrow', 'Due This Week', 'Due Later'],
            'datasets': [{
                'label': 'Amount (KES)',
                'data': [
                    float(summary.get('today_due_amount', 0)),
                    float(summary.get('tomorrow_due_amount', 0)),
                    float(summary.get('week_due_amount', 0)),
                    float(summary.get('later_due_amount', 0))
                ],
                'backgroundColor': [colors['danger'], colors['warning'], colors['info'], colors['primary']],
                'borderColor': [colors['danger'], colors['warning'], colors['info'], colors['primary']],
                'borderWidth': 1
            }],
            'formatCurrency': True
        }
        
        # Loan count distribution
        charts['due_count_distribution'] = {
            'type': 'doughnut',
            'title': 'Distribution of Loans Due by Count',
            'labels': ['Due Today', 'Due Tomorrow', 'Due This Week', 'Due Later'],
            'datasets': [{
                'data': [
                    summary.get('today_due_count', 0),
                    summary.get('tomorrow_due_count', 0),
                    summary.get('week_due_count', 0),
                    summary.get('later_due_count', 0)
                ],
                'backgroundColor': [colors['danger'], colors['warning'], colors['info'], colors['primary']],
                'borderWidth': 2,
                'borderColor': colors['background']
            }]
        }
        
        return charts
    
    def generate_delinquent_charts(self, data):
        """Generate chart configs for delinquent loans report"""
        charts = {}
        
        # Aging analysis
        if 'aging_buckets' in data:
            aging_data = data['aging_buckets']
            charts['aging_analysis'] = {
                'type': 'bar',
                'title': 'Delinquent Loans Aging Analysis',
                'labels': list(aging_data.keys()),
                'datasets': [{
                    'label': 'Amount (KES)',
                    'data': list(aging_data.values()),
                    'backgroundColor': ['#f39c12', '#e74c3c', '#8b0000'],
                    'borderColor': ['#d68910', '#c0392b', '#660000'],
                    'borderWidth': 1
                }]
            }
        
        return charts
    
    def generate_arrears_charts(self, data):
        """Generate chart configs for arrears report"""
        charts = {}
        
        
        return charts
    
    def generate_processing_fees_charts(self, data):
        """Generate chart configs for processing fees report"""
        charts = {}
        
        # Monthly revenue trend
        if 'monthly_revenue' in data:
            monthly_data = data['monthly_revenue']
            charts['revenue_trend'] = {
                'type': 'line',
                'title': 'Processing Fee Revenue Trend',
                'labels': monthly_data.get('months', []),
                'datasets': [{
                    'label': 'Revenue (KES)',
                    'data': monthly_data.get('amounts', []),
                    'borderColor': '#27ae60',
                    'backgroundColor': 'rgba(39, 174, 96, 0.1)',
                    'borderWidth': 2,
                    'fill': True,
                    'tension': 0.4
                }]
            }
        
        return charts
    
    def generate_interest_charts(self, data):
        """Generate chart configs for interest income report"""
        charts = {}
        
        # Product performance
        if 'product_performance' in data:
            product_data = data['product_performance']
            charts['product_performance'] = {
                'type': 'bar',
                'title': 'Interest Income by Product Type',
                'labels': list(product_data.keys()),
                'datasets': [{
                    'label': 'Interest Income (KES)',
                    'data': list(product_data.values()),
                    'backgroundColor': ['#3498db', '#e74c3c', '#2ecc71', '#f39c12'],
                    'borderColor': ['#2980b9', '#c0392b', '#27ae60', '#d68910'],
                    'borderWidth': 1
                }]
            }
        
        return charts
    
    def generate_registration_charts(self, data):
        """Generate chart configs for registration fees report"""
        charts = {}
        
        # Product breakdown
        if 'product_breakdown' in data:
            product_data = data['product_breakdown']
            charts['product_breakdown'] = {
                'type': 'pie',
                'title': 'Registration Fees by Product Type',
                'labels': list(product_data.keys()),
                'datasets': [{
                    'data': list(product_data.values()),
                    'backgroundColor': ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6'],
                    'borderWidth': 2,
                    'borderColor': '#ffffff'
                }]
            }
        
        return charts
    
    def generate_dashboard_charts(self, data):
        """Generate chart configs for dashboard overview"""
        charts = {}
        
        # Portfolio overview
        portfolio_data = {
            'Active Loans': data.get('loans_due', {}).get('summary', {}).get('total_active', 0),
            'Delinquent': data.get('delinquent', {}).get('summary', {}).get('total_delinquent', 0),
            'Completed': data.get('loans_due', {}).get('summary', {}).get('total_completed', 0)
        }
        
        charts['portfolio_overview'] = {
            'type': 'doughnut',
            'title': 'Portfolio Overview',
            'labels': list(portfolio_data.keys()),
            'datasets': [{
                'data': list(portfolio_data.values()),
                'backgroundColor': ['#2ecc71', '#e74c3c', '#3498db'],
                'borderWidth': 2,
                'borderColor': '#ffffff'
            }]
        }
        
        return charts
    
    def generate_summary_data(self, data):
        """
        Generate summary statistics for dashboard cards
        """
        summary = {}
        
        try:
            if isinstance(data, dict):
                # Extract key metrics based on data structure
                if 'summary' in data:
                    summary.update(data['summary'])
                
                # Calculate additional metrics
                if 'loans' in data:
                    summary['total_loans'] = len(data['loans'])
                
                if 'total_amount' in data:
                    summary['total_amount'] = data['total_amount']
                
        except Exception as e:
            logger.error(f"Error generating summary data: {str(e)}")
        
        return summary


@require_http_methods(["GET"])
@login_required
def get_chart_data(request, report_type, chart_type):
    """
    Get specific chart data for a report type
    """
    try:
        start_date = request.GET.get('start_date')
        end_date = request.GET.get('end_date')
        
        if not start_date or not end_date:
            return JsonResponse({'error': 'Date range required'}, status=400)
        
        start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
        end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
        
        # Get the specific chart data
        reports_service = ComprehensiveReportsService()
        chart_service = ChartGenerationService()
        
        # Get report data
        if report_type == 'loans_due':
            report_data = reports_service.get_loans_due_report(start_date, end_date)
        elif report_type == 'delinquent_loans':
            report_data = reports_service.get_delinquent_loans_report({'start_date': start_date, 'end_date': end_date})
        else:
            return JsonResponse({'error': 'Invalid report type'}, status=400)
        
        # Generate specific chart
        if chart_type == 'web':
            chart_config = chart_service.generate_chart_for_web('bar', report_data)
            return JsonResponse({'chart_config': json.loads(chart_config)})
        else:
            return JsonResponse({'error': 'Invalid chart type'}, status=400)
        
    except Exception as e:
        logger.error(f"Error in get_chart_data: {str(e)}")
        return JsonResponse({'error': str(e)}, status=500)


@require_http_methods(["POST"])
@login_required
@csrf_exempt
def update_chart_preferences(request):
    """
    Update user chart preferences
    """
    try:
        data = json.loads(request.body)
        chart_id = data.get('chart_id')
        preferences = data.get('preferences', {})
        
        # Save preferences to user profile or session
        request.session[f'chart_prefs_{chart_id}'] = preferences
        
        return JsonResponse({'success': True})
        
    except Exception as e:
        logger.error(f"Error updating chart preferences: {str(e)}")
        return JsonResponse({'error': str(e)}, status=500)