"""
Physicians Console UI views - Server-rendered templates for physician management
"""
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Avg, Count, Q
from django.shortcuts import get_object_or_404, render
from django.utils import timezone

from apps.organizations.models import Department, Hospital, Staff

from .models import PhysicianMonthlyRating


@login_required
def physician_list(request):
    """
    Physicians list view with filters.

    Features:
    - Server-side pagination
    - Filters (hospital, department, specialization, status)
    - Search by name or license number
    - Current month rating display
    """
    # Base queryset with optimizations
    queryset = Staff.objects.select_related('hospital', 'department')

    # Apply RBAC filters
    user = request.user
    if user.is_px_admin():
        pass  # See all
    elif user.hospital:
        queryset = queryset.filter(hospital=user.hospital)
    else:
        queryset = queryset.none()

    # Apply filters
    hospital_filter = request.GET.get('hospital')
    if hospital_filter:
        queryset = queryset.filter(hospital_id=hospital_filter)

    department_filter = request.GET.get('department')
    if department_filter:
        queryset = queryset.filter(department_id=department_filter)

    specialization_filter = request.GET.get('specialization')
    if specialization_filter:
        queryset = queryset.filter(specialization__icontains=specialization_filter)

    status_filter = request.GET.get('status', 'active')
    if status_filter:
        queryset = queryset.filter(status=status_filter)

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(license_number__icontains=search_query) |
            Q(specialization__icontains=search_query)
        )

    # Ordering
    order_by = request.GET.get('order_by', 'last_name')
    queryset = queryset.order_by(order_by)

    # Pagination
    page_size = int(request.GET.get('page_size', 25))
    paginator = Paginator(queryset, page_size)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)

    # Get current month ratings for displayed physicians
    now = timezone.now()
    physician_ids = [p.id for p in page_obj.object_list]
    current_ratings = PhysicianMonthlyRating.objects.filter(
        staff_id__in=physician_ids,
        year=now.year,
        month=now.month
    ).select_related('staff')

    # Create rating lookup
    ratings_dict = {r.staff_id: r for r in current_ratings}

    # Attach ratings to physicians
    for physician in page_obj.object_list:
        physician.current_rating = ratings_dict.get(physician.id)

    # Get filter options
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    departments = Department.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        departments = departments.filter(hospital=user.hospital)

    # Get unique specializations
    specializations = Staff.objects.values_list('specialization', flat=True).distinct().order_by('specialization')

    # Statistics
    stats = {
        'total': queryset.count(),
        'active': queryset.filter(status='active').count(),
    }

    context = {
        'page_obj': page_obj,
        'physicians': page_obj.object_list,
        'stats': stats,
        'hospitals': hospitals,
        'departments': departments,
        'specializations': specializations,
        'filters': request.GET,
        'current_year': now.year,
        'current_month': now.month,
    }

    return render(request, 'physicians/physician_list.html', context)


@login_required
def physician_detail(request, pk):
    """
    Physician detail view with performance metrics.

    Features:
    - Full physician details
    - Current month rating
    - Year-to-date performance
    - Monthly ratings history (last 12 months)
    - Performance trends
    """
    physician = get_object_or_404(
        Staff.objects.select_related('hospital', 'department'),
        pk=pk
    )

    # Check permission
    user = request.user
    if not user.is_px_admin() and user.hospital:
        if physician.hospital != user.hospital:
            from django.http import Http404
            raise Http404("Physician not found")

    now = timezone.now()
    current_year = now.year
    current_month = now.month

    # Get current month rating
    current_month_rating = PhysicianMonthlyRating.objects.filter(
        staff=physician,
        year=current_year,
        month=current_month
    ).first()

    # Get previous month rating
    prev_month = current_month - 1 if current_month > 1 else 12
    prev_year = current_year if current_month > 1 else current_year - 1
    previous_month_rating = PhysicianMonthlyRating.objects.filter(
        staff=physician,
        year=prev_year,
        month=prev_month
    ).first()

    # Get year-to-date stats
    ytd_ratings = PhysicianMonthlyRating.objects.filter(
        staff=physician,
        year=current_year
    )

    ytd_stats = ytd_ratings.aggregate(
        avg_rating=Avg('average_rating'),
        total_surveys=Count('id')
    )

    # Get last 12 months ratings
    ratings_history = PhysicianMonthlyRating.objects.filter(
        staff=physician
    ).order_by('-year', '-month')[:12]

    # Get best and worst months from all ratings (not just last 12 months)
    all_ratings = PhysicianMonthlyRating.objects.filter(staff=physician)
    best_month = all_ratings.order_by('-average_rating').first()
    worst_month = all_ratings.order_by('average_rating').first()

    # Determine trend
    trend = 'stable'
    trend_percentage = 0
    if current_month_rating and previous_month_rating:
        diff = float(current_month_rating.average_rating - previous_month_rating.average_rating)
        if previous_month_rating.average_rating > 0:
            trend_percentage = (diff / float(previous_month_rating.average_rating)) * 100

        if diff > 0.1:
            trend = 'improving'
        elif diff < -0.1:
            trend = 'declining'

    context = {
        'physician': physician,
        'current_month_rating': current_month_rating,
        'previous_month_rating': previous_month_rating,
        'ytd_average': ytd_stats['avg_rating'],
        'ytd_surveys': ytd_stats['total_surveys'],
        'ratings_history': ratings_history,
        'best_month': best_month,
        'worst_month': worst_month,
        'trend': trend,
        'trend_percentage': abs(trend_percentage),
        'current_year': current_year,
        'current_month': current_month,
    }

    return render(request, 'physicians/physician_detail.html', context)


@login_required
def leaderboard(request):
    """
    Physician leaderboard view.

    Features:
    - Top-rated physicians for selected period
    - Filters (hospital, department, month/year)
    - Ranking with trends
    - Performance distribution
    """
    # Get parameters
    now = timezone.now()
    year = int(request.GET.get('year', now.year))
    month = int(request.GET.get('month', now.month))
    hospital_filter = request.GET.get('hospital')
    department_filter = request.GET.get('department')
    limit = int(request.GET.get('limit', 20))

    # Build queryset
    queryset = PhysicianMonthlyRating.objects.filter(
        year=year,
        month=month
    ).select_related('staff', 'staff__hospital', 'staff__department')

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(staff__hospital=user.hospital)

    # Apply filters
    if hospital_filter:
        queryset = queryset.filter(staff__hospital_id=hospital_filter)

    if department_filter:
        queryset = queryset.filter(staff__department_id=department_filter)

    # Order by rating
    queryset = queryset.order_by('-average_rating')[:limit]

    # Get previous month for trend
    prev_month = month - 1 if month > 1 else 12
    prev_year = year if month > 1 else year - 1

    # Build leaderboard with trends
    leaderboard = []
    for rank, rating in enumerate(queryset, start=1):
        # Get previous month rating for trend
        prev_rating = PhysicianMonthlyRating.objects.filter(
            staff=rating.staff,
            year=prev_year,
            month=prev_month
        ).first()

        trend = 'stable'
        trend_value = 0
        if prev_rating:
            diff = float(rating.average_rating - prev_rating.average_rating)
            trend_value = diff
            if diff > 0.1:
                trend = 'up'
            elif diff < -0.1:
                trend = 'down'

        leaderboard.append({
            'rank': rank,
            'rating': rating,
            'physician': rating.staff,
            'trend': trend,
            'trend_value': trend_value,
            'prev_rating': prev_rating
        })

    # Get filter options
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    departments = Department.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        departments = departments.filter(hospital=user.hospital)

    # Calculate statistics
    all_ratings = PhysicianMonthlyRating.objects.filter(year=year, month=month)
    if not user.is_px_admin() and user.hospital:
        all_ratings = all_ratings.filter(staff__hospital=user.hospital)

    stats = all_ratings.aggregate(
        total_physicians=Count('id'),
        average_rating=Avg('average_rating'),
        total_surveys=Count('total_surveys')
    )

    # Distribution
    excellent = all_ratings.filter(average_rating__gte=4.5).count()
    good = all_ratings.filter(average_rating__gte=3.5, average_rating__lt=4.5).count()
    average = all_ratings.filter(average_rating__gte=2.5, average_rating__lt=3.5).count()
    poor = all_ratings.filter(average_rating__lt=2.5).count()

    context = {
        'leaderboard': leaderboard,
        'year': year,
        'month': month,
        'hospitals': hospitals,
        'departments': departments,
        'filters': request.GET,
        'stats': stats,
        'distribution': {
            'excellent': excellent,
            'good': good,
            'average': average,
            'poor': poor
        }
    }

    return render(request, 'physicians/leaderboard.html', context)


@login_required
def ratings_list(request):
    """
    Monthly ratings list view with filters.

    Features:
    - All monthly ratings
    - Filters (physician, hospital, department, year, month)
    - Search by physician name
    - Pagination
    """
    # Base queryset
    queryset = PhysicianMonthlyRating.objects.select_related(
        'staff', 'staff__hospital', 'staff__department'
    )

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(staff__hospital=user.hospital)

    # Apply filters
    physician_filter = request.GET.get('physician')
    if physician_filter:
        queryset = queryset.filter(staff_id=physician_filter)

    hospital_filter = request.GET.get('hospital')
    if hospital_filter:
        queryset = queryset.filter(staff__hospital_id=hospital_filter)

    department_filter = request.GET.get('department')
    if department_filter:
        queryset = queryset.filter(staff__department_id=department_filter)

    year_filter = request.GET.get('year')
    if year_filter:
        queryset = queryset.filter(year=int(year_filter))

    month_filter = request.GET.get('month')
    if month_filter:
        queryset = queryset.filter(month=int(month_filter))

    # Search
    search_query = request.GET.get('search')
    if search_query:
        queryset = queryset.filter(
            Q(staff__first_name__icontains=search_query) |
            Q(staff__last_name__icontains=search_query) |
            Q(staff__license_number__icontains=search_query)
        )

    # Ordering
    order_by = request.GET.get('order_by', '-year,-month,-average_rating')
    queryset = queryset.order_by(*order_by.split(','))

    # Pagination
    page_size = int(request.GET.get('page_size', 25))
    paginator = Paginator(queryset, page_size)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)

    # Get filter options
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    departments = Department.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        departments = departments.filter(hospital=user.hospital)

    # Get available years
    years = PhysicianMonthlyRating.objects.values_list('year', flat=True).distinct().order_by('-year')

    context = {
        'page_obj': page_obj,
        'ratings': page_obj.object_list,
        'hospitals': hospitals,
        'departments': departments,
        'years': years,
        'filters': request.GET,
    }

    return render(request, 'physicians/ratings_list.html', context)


@login_required
def specialization_overview(request):
    """
    Specialization overview - aggregated ratings by specialization.

    Features:
    - Average rating per specialization
    - Total physicians per specialization
    - Total surveys per specialization
    - Drill-down to physicians in specialization
    """
    # Get parameters
    now = timezone.now()
    year = int(request.GET.get('year', now.year))
    month = int(request.GET.get('month', now.month))
    hospital_filter = request.GET.get('hospital')

    # Base queryset
    queryset = PhysicianMonthlyRating.objects.filter(
        year=year,
        month=month
    ).select_related('staff', 'staff__hospital', 'staff__department')

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(staff__hospital=user.hospital)

    # Apply filters
    if hospital_filter:
        queryset = queryset.filter(staff__hospital_id=hospital_filter)

    # Aggregate by specialization
    from django.db.models import Avg, Count, Sum

    specialization_data = {}
    for rating in queryset:
        spec = rating.staff.specialization
        if spec not in specialization_data:
            specialization_data[spec] = {
                'specialization': spec,
                'physicians': [],
                'total_physicians': 0,
                'total_surveys': 0,
                'total_positive': 0,
                'total_neutral': 0,
                'total_negative': 0,
                'ratings_sum': 0,
            }

        specialization_data[spec]['physicians'].append(rating)
        specialization_data[spec]['total_physicians'] += 1
        specialization_data[spec]['total_surveys'] += rating.total_surveys
        specialization_data[spec]['total_positive'] += rating.positive_count
        specialization_data[spec]['total_neutral'] += rating.neutral_count
        specialization_data[spec]['total_negative'] += rating.negative_count
        specialization_data[spec]['ratings_sum'] += float(rating.average_rating)

    # Calculate averages
    specializations = []
    for spec, data in specialization_data.items():
        avg_rating = data['ratings_sum'] / data['total_physicians'] if data['total_physicians'] > 0 else 0
        specializations.append({
            'specialization': spec,
            'total_physicians': data['total_physicians'],
            'average_rating': round(avg_rating, 2),
            'total_surveys': data['total_surveys'],
            'positive_count': data['total_positive'],
            'neutral_count': data['total_neutral'],
            'negative_count': data['total_negative'],
            'physicians': sorted(data['physicians'], key=lambda x: x.average_rating, reverse=True)
        })

    # Sort by average rating
    specializations.sort(key=lambda x: x['average_rating'], reverse=True)

    # Get filter options
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    context = {
        'specializations': specializations,
        'year': year,
        'month': month,
        'hospitals': hospitals,
        'filters': request.GET,
    }

    return render(request, 'physicians/specialization_overview.html', context)


@login_required
def department_overview(request):
    """
    Department overview - aggregated ratings by department.

    Features:
    - Average rating per department
    - Total physicians per department
    - Total surveys per department
    - Drill-down to physicians in department
    """
    # Get parameters
    now = timezone.now()
    year = int(request.GET.get('year', now.year))
    month = int(request.GET.get('month', now.month))
    hospital_filter = request.GET.get('hospital')

    # Base queryset
    queryset = PhysicianMonthlyRating.objects.filter(
        year=year,
        month=month
    ).select_related('staff', 'staff__hospital', 'staff__department')

    # Apply RBAC filters
    user = request.user
    if not user.is_px_admin() and user.hospital:
        queryset = queryset.filter(staff__hospital=user.hospital)

    # Apply filters
    if hospital_filter:
        queryset = queryset.filter(staff__hospital_id=hospital_filter)

    # Aggregate by department
    from django.db.models import Avg, Count, Sum

    department_data = {}
    for rating in queryset:
        dept = rating.staff.department
        if not dept:
            continue

        dept_key = str(dept.id)
        if dept_key not in department_data:
            department_data[dept_key] = {
                'department': dept,
                'physicians': [],
                'total_physicians': 0,
                'total_surveys': 0,
                'total_positive': 0,
                'total_neutral': 0,
                'total_negative': 0,
                'ratings_sum': 0,
            }

        department_data[dept_key]['physicians'].append(rating)
        department_data[dept_key]['total_physicians'] += 1
        department_data[dept_key]['total_surveys'] += rating.total_surveys
        department_data[dept_key]['total_positive'] += rating.positive_count
        department_data[dept_key]['total_neutral'] += rating.neutral_count
        department_data[dept_key]['total_negative'] += rating.negative_count
        department_data[dept_key]['ratings_sum'] += float(rating.average_rating)

    # Calculate averages
    departments = []
    for dept_key, data in department_data.items():
        avg_rating = data['ratings_sum'] / data['total_physicians'] if data['total_physicians'] > 0 else 0
        departments.append({
            'department': data['department'],
            'total_physicians': data['total_physicians'],
            'average_rating': round(avg_rating, 2),
            'total_surveys': data['total_surveys'],
            'positive_count': data['total_positive'],
            'neutral_count': data['total_neutral'],
            'negative_count': data['total_negative'],
            'physicians': sorted(data['physicians'], key=lambda x: x.average_rating, reverse=True)
        })

    # Sort by average rating
    departments.sort(key=lambda x: x['average_rating'], reverse=True)

    # Get filter options
    hospitals = Hospital.objects.filter(status='active')
    if not user.is_px_admin() and user.hospital:
        hospitals = hospitals.filter(id=user.hospital.id)

    context = {
        'departments': departments,
        'year': year,
        'month': month,
        'hospitals': hospitals,
        'filters': request.GET,
    }

    return render(request, 'physicians/department_overview.html', context)
