"""
Views for Portfolio Snapshot Management and Health Score Monitoring

These views provide interfaces for viewing portfolio snapshots, health scores,
growth trends, and performance alerts.
"""

from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.utils import timezone
from django.db.models import Q, Avg, Sum, Count
from django.core.paginator import Paginator
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.views import View
from datetime import date, timedelta, datetime
import json
from decimal import Decimal

from .models import CustomUser, Branch
from .enhanced_permissions_models import PortfolioSnapshot, ClientGrowthMetrics
from .portfolio_snapshot_service import PortfolioSnapshotService
from utils.models import Notification


@login_required
def portfolio_snapshot_dashboard(request):
    """
    Main dashboard for portfolio snapshot overview
    """
    # Get current user's role and permissions
    user = request.user
    
    # Determine which managers to show based on user role
    if user.role == 'admin':
        managers = CustomUser.objects.filter(
            role__in=['loan_officer', 'team_leader'],
            is_active=True
        ).select_related('branch')
    elif user.role == 'team_leader':
        managers = CustomUser.objects.filter(
            role='loan_officer',
            branch=user.branch,
            is_active=True
        ).select_related('branch')
        # Include the team leader themselves
        managers = managers.union(CustomUser.objects.filter(id=user.id))
    elif user.role == 'loan_officer':
        managers = CustomUser.objects.filter(id=user.id)
    else:
        managers = CustomUser.objects.none()
    
    # Get latest snapshots for each manager
    today = timezone.now().date()
    latest_snapshots = []
    
    for manager in managers:
        snapshot = PortfolioSnapshot.objects.filter(
            manager=manager,
            snapshot_date__lte=today
        ).order_by('-snapshot_date').first()
        
        if snapshot:
            latest_snapshots.append({
                'manager': manager,
                'snapshot': snapshot,
                'health_score': snapshot.get_portfolio_health_score(),
                'growth_rate': snapshot.calculate_growth_rate()
            })
    
    # Calculate summary statistics
    total_clients = sum(s['snapshot'].total_clients for s in latest_snapshots)
    total_active_loans = sum(s['snapshot'].active_loans for s in latest_snapshots)
    total_outstanding = sum(s['snapshot'].total_outstanding for s in latest_snapshots)
    avg_health_score = sum(s['health_score'] for s in latest_snapshots) / len(latest_snapshots) if latest_snapshots else 0
    
    # Get recent alerts
    recent_alerts = Notification.objects.filter(
        user=user,
        notification_type__in=[
            'portfolio_alert', 'portfolio_health_critical', 'portfolio_health_warning',
            'high_default_rate', 'low_collection_rate', 'high_par'
        ],
        created_at__gte=timezone.now() - timedelta(days=7)
    ).order_by('-created_at')[:10]
    
    context = {
        'latest_snapshots': latest_snapshots,
        'summary_stats': {
            'total_clients': total_clients,
            'total_active_loans': total_active_loans,
            'total_outstanding': total_outstanding,
            'avg_health_score': round(avg_health_score, 1),
            'managers_count': len(latest_snapshots)
        },
        'recent_alerts': recent_alerts,
        'user_role': user.role,
        'today': today
    }
    
    return render(request, 'users/portfolio_snapshot_dashboard.html', context)


@login_required
def manager_portfolio_detail(request, manager_id):
    """
    Detailed portfolio view for a specific manager
    """
    manager = get_object_or_404(CustomUser, id=manager_id, role__in=['loan_officer', 'team_leader'])
    
    # Check permissions
    user = request.user
    if user.role not in ['admin'] and user.role != 'team_leader' and user.id != manager.id:
        if user.role == 'team_leader' and manager.branch != user.branch:
            return JsonResponse({'error': 'Permission denied'}, status=403)
    
    # Get date range from request
    days = int(request.GET.get('days', 30))
    end_date = timezone.now().date()
    start_date = end_date - timedelta(days=days)
    
    # Get snapshots for the period
    snapshots = PortfolioSnapshot.objects.filter(
        manager=manager,
        snapshot_date__range=[start_date, end_date]
    ).order_by('snapshot_date')
    
    # Redirect to the standard portfolio manager detail view
    from django.shortcuts import redirect
    from django.urls import reverse
    return redirect(reverse('users:portfolio_manager_detail', args=[manager_id]))


@login_required
@require_http_methods(["GET"])
def portfolio_trends_api(request, manager_id):
    """
    API endpoint for portfolio trends data (for charts)
    """
    manager = get_object_or_404(CustomUser, id=manager_id, role__in=['loan_officer', 'team_leader'])
    
    # Check permissions
    user = request.user
    if user.role not in ['admin'] and user.role != 'team_leader' and user.id != manager.id:
        if user.role == 'team_leader' and manager.branch != user.branch:
            return JsonResponse({'error': 'Permission denied'}, status=403)
    
    # Get parameters
    days = int(request.GET.get('days', 30))
    metric = request.GET.get('metric', 'health_score')
    
    # Get snapshots
    end_date = timezone.now().date()
    start_date = end_date - timedelta(days=days)
    
    snapshots = PortfolioSnapshot.objects.filter(
        manager=manager,
        snapshot_date__range=[start_date, end_date]
    ).order_by('snapshot_date')
    
    # Prepare data based on requested metric
    data = []
    for snapshot in snapshots:
        point = {
            'date': snapshot.snapshot_date.isoformat(),
            'value': 0
        }
        
        if metric == 'health_score':
            point['value'] = float(snapshot.get_portfolio_health_score())
        elif metric == 'total_clients':
            point['value'] = snapshot.total_clients
        elif metric == 'active_loans':
            point['value'] = snapshot.active_loans
        elif metric == 'collection_rate':
            point['value'] = float(snapshot.collection_rate)
        elif metric == 'default_rate':
            point['value'] = float(snapshot.default_rate)
        elif metric == 'total_outstanding':
            point['value'] = float(snapshot.total_outstanding)
        elif metric == 'par_30':
            point['value'] = float(snapshot.par_30)
        
        data.append(point)
    
    return JsonResponse({
        'data': data,
        'metric': metric,
        'period': f"{start_date} to {end_date}",
        'manager': manager.get_full_name()
    })


@login_required
@staff_member_required
def generate_snapshot_manual(request):
    """
    Manual snapshot generation interface for administrators
    """
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            target_date_str = data.get('date')
            manager_id = data.get('manager_id')
            
            # Parse date
            if target_date_str:
                target_date = datetime.strptime(target_date_str, '%Y-%m-%d').date()
            else:
                target_date = timezone.now().date()
            
            snapshot_service = PortfolioSnapshotService()
            
            if manager_id:
                # Generate for specific manager
                manager = get_object_or_404(CustomUser, id=manager_id, role__in=['loan_officer', 'team_leader'])
                
                snapshot_data = snapshot_service._calculate_portfolio_metrics(manager, target_date)
                
                snapshot, created = PortfolioSnapshot.objects.update_or_create(
                    manager=manager,
                    snapshot_date=target_date,
                    defaults=snapshot_data
                )
                
                health_score = snapshot.get_portfolio_health_score()
                snapshot_service._check_performance_alerts(manager, snapshot, health_score)
                
                return JsonResponse({
                    'success': True,
                    'message': f"Snapshot {'created' if created else 'updated'} for {manager.get_full_name()}",
                    'health_score': float(health_score)
                })
            else:
                # Generate for all managers
                results = snapshot_service.generate_daily_snapshots(target_date)
                
                return JsonResponse({
                    'success': results['success'],
                    'message': f"Generated {results['snapshots_generated']} snapshots, updated {results['snapshots_updated']}",
                    'results': results
                })
                
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': str(e)
            }, status=500)
    
    # GET request - show the form
    managers = CustomUser.objects.filter(
        role__in=['loan_officer', 'team_leader'],
        is_active=True
    ).select_related('branch').order_by('first_name', 'last_name')
    
    context = {
        'managers': managers,
        'today': timezone.now().date()
    }
    
    return render(request, 'users/generate_snapshot_manual.html', context)


@login_required
def portfolio_health_alerts(request):
    """
    View for managing portfolio health alerts
    """
    user = request.user
    
    # Get alerts based on user role
    if user.role == 'admin':
        alerts = Notification.objects.filter(
            notification_type__in=[
                'portfolio_alert', 'portfolio_health_critical', 'portfolio_health_warning',
                'high_default_rate', 'low_collection_rate', 'high_par', 'negative_growth'
            ]
        )
    elif user.role == 'team_leader':
        # Get alerts for loan officers in the same branch
        branch_users = CustomUser.objects.filter(
            branch=user.branch,
            role__in=['loan_officer', 'team_leader']
        )
        alerts = Notification.objects.filter(
            user__in=branch_users,
            notification_type__in=[
                'portfolio_alert', 'portfolio_health_critical', 'portfolio_health_warning',
                'high_default_rate', 'low_collection_rate', 'high_par', 'negative_growth'
            ]
        )
    else:
        # Regular users see only their own alerts
        alerts = Notification.objects.filter(
            user=user,
            notification_type__in=[
                'portfolio_alert', 'portfolio_health_critical', 'portfolio_health_warning',
                'high_default_rate', 'low_collection_rate', 'high_par', 'negative_growth'
            ]
        )
    
    # Filter by parameters
    priority = request.GET.get('priority')
    if priority:
        alerts = alerts.filter(priority=priority)
    
    alert_type = request.GET.get('type')
    if alert_type:
        alerts = alerts.filter(notification_type=alert_type)
    
    unread_only = request.GET.get('unread_only') == 'true'
    if unread_only:
        alerts = alerts.filter(read_at__isnull=True)
    
    # Order by priority and date
    priority_order = {'urgent': 1, 'high': 2, 'medium': 3, 'low': 4}
    alerts = alerts.order_by('-created_at')
    
    # Paginate
    paginator = Paginator(alerts, 25)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Get summary statistics
    alert_stats = {
        'total': alerts.count(),
        'unread': alerts.filter(read_at__isnull=True).count(),
        'critical': alerts.filter(priority='high').count(),
        'action_required': alerts.filter(action_required=True).count()
    }
    
    context = {
        'alerts': page_obj,
        'alert_stats': alert_stats,
        'filters': {
            'priority': priority,
            'type': alert_type,
            'unread_only': unread_only
        }
    }
    
    return render(request, 'users/portfolio_health_alerts.html', context)


@login_required
@require_http_methods(["POST"])
def mark_alert_read(request, alert_id):
    """
    Mark a portfolio alert as read
    """
    try:
        alert = get_object_or_404(Notification, id=alert_id)
        
        # Check permissions
        user = request.user
        if user.role not in ['admin'] and alert.user != user:
            if user.role == 'team_leader' and alert.user.branch != user.branch:
                return JsonResponse({'error': 'Permission denied'}, status=403)
        
        alert.mark_as_read()
        
        return JsonResponse({
            'success': True,
            'message': 'Alert marked as read'
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e)
        }, status=500)


@login_required
def portfolio_comparison(request):
    """
    Compare portfolio performance across managers
    """
    user = request.user
    
    # Determine which managers to compare based on user role
    if user.role == 'admin':
        managers = CustomUser.objects.filter(
            role__in=['loan_officer', 'team_leader'],
            is_active=True
        ).select_related('branch')
    elif user.role == 'team_leader':
        managers = CustomUser.objects.filter(
            role='loan_officer',
            branch=user.branch,
            is_active=True
        ).select_related('branch')
    else:
        return JsonResponse({'error': 'Permission denied'}, status=403)
    
    # Get comparison period
    days = int(request.GET.get('days', 30))
    end_date = timezone.now().date()
    start_date = end_date - timedelta(days=days)
    
    # Get latest snapshots for each manager
    comparison_data = []
    
    for manager in managers:
        latest_snapshot = PortfolioSnapshot.objects.filter(
            manager=manager,
            snapshot_date__range=[start_date, end_date]
        ).order_by('-snapshot_date').first()
        
        if latest_snapshot:
            # Calculate growth rate
            previous_snapshot = PortfolioSnapshot.objects.filter(
                manager=manager,
                snapshot_date__lt=latest_snapshot.snapshot_date
            ).order_by('-snapshot_date').first()
            
            growth_rate = latest_snapshot.calculate_growth_rate(previous_snapshot) if previous_snapshot else 0
            
            comparison_data.append({
                'manager': manager,
                'snapshot': latest_snapshot,
                'health_score': latest_snapshot.get_portfolio_health_score(),
                'growth_rate': growth_rate,
                'par_30_percentage': (latest_snapshot.par_30 / latest_snapshot.total_outstanding * 100) if latest_snapshot.total_outstanding > 0 else 0
            })
    
    # Sort by health score (descending)
    comparison_data.sort(key=lambda x: x['health_score'], reverse=True)
    
    context = {
        'comparison_data': comparison_data,
        'period': {
            'start': start_date,
            'end': end_date,
            'days': days
        },
        'user_role': user.role
    }
    
    return render(request, 'users/portfolio_comparison.html', context)


@login_required
@require_http_methods(["GET"])
def export_portfolio_data(request, manager_id):
    """
    Export portfolio data as CSV
    """
    manager = get_object_or_404(CustomUser, id=manager_id, role__in=['loan_officer', 'team_leader'])
    
    # Check permissions
    user = request.user
    if user.role not in ['admin'] and user.role != 'team_leader' and user.id != manager.id:
        if user.role == 'team_leader' and manager.branch != user.branch:
            return JsonResponse({'error': 'Permission denied'}, status=403)
    
    # Get date range
    days = int(request.GET.get('days', 90))
    end_date = timezone.now().date()
    start_date = end_date - timedelta(days=days)
    
    # Get snapshots
    snapshots = PortfolioSnapshot.objects.filter(
        manager=manager,
        snapshot_date__range=[start_date, end_date]
    ).order_by('snapshot_date')
    
    # Create CSV response
    import csv
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = f'attachment; filename="portfolio_data_{manager.username}_{start_date}_to_{end_date}.csv"'
    
    writer = csv.writer(response)
    
    # Write header
    writer.writerow([
        'Date', 'Manager', 'Branch', 'Total Clients', 'Active Clients', 'Active Loans',
        'Total Disbursed', 'Total Outstanding', 'Total Collected', 'Collection Rate',
        'Default Rate', 'PAR 30', 'PAR 60', 'PAR 90', 'Health Score', 'Portfolio Yield',
        'Average Loan Size', 'New Clients', 'New Loans', 'Daily Disbursements', 'Daily Collections'
    ])
    
    # Write data
    for snapshot in snapshots:
        health_score = snapshot.get_portfolio_health_score()
        writer.writerow([
            snapshot.snapshot_date,
            snapshot.manager.get_full_name(),
            snapshot.branch.name if snapshot.branch else 'No Branch',
            snapshot.total_clients,
            snapshot.active_clients,
            snapshot.active_loans,
            snapshot.total_disbursed,
            snapshot.total_outstanding,
            snapshot.total_collected,
            snapshot.collection_rate,
            snapshot.default_rate,
            snapshot.par_30,
            snapshot.par_60,
            snapshot.par_90,
            health_score,
            snapshot.portfolio_yield,
            snapshot.average_loan_size,
            snapshot.new_clients,
            snapshot.new_loans,
            snapshot.daily_disbursements,
            snapshot.daily_collections
        ])
    
    return response