"""
KPI Report Views

Views for listing, viewing, and generating KPI reports.
Follows the PX360 UI patterns with Tailwind, Lucide icons, and HTMX.
"""

import json
import logging
from datetime import datetime

from django.contrib import messages

logger = logging.getLogger(__name__)
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_POST

from apps.organizations.models import Hospital

from .kpi_models import KPIReport, KPIReportStatus, KPIReportType
from .kpi_service import KPICalculationService


@login_required
def kpi_report_list(request):
    """
    KPI Report list view

    Shows all KPI reports with filtering by:
    - Report type
    - Hospital
    - Year/Month
    - Status
    """
    user = request.user

    # Base queryset
    queryset = KPIReport.objects.select_related("hospital", "generated_by")

    # Apply hospital filter based on user role
    if not user.is_px_admin():
        if user.hospital:
            queryset = queryset.filter(hospital=user.hospital)
        else:
            queryset = KPIReport.objects.none()
    else:
        hospital_filter = request.GET.get("hospital")
        if hospital_filter:
            queryset = queryset.filter(hospital_id=hospital_filter)
        elif request.tenant_hospital:
            queryset = queryset.filter(hospital=request.tenant_hospital)

    # Apply filters from request
    report_type = request.GET.get("report_type")
    if report_type:
        queryset = queryset.filter(report_type=report_type)

    year = request.GET.get("year")
    if year:
        queryset = queryset.filter(year=year)

    month = request.GET.get("month")
    if month:
        queryset = queryset.filter(month=month)

    status = request.GET.get("status")
    if status:
        queryset = queryset.filter(status=status)

    # Ordering
    queryset = queryset.order_by("-year", "-month", "report_type")

    # Calculate statistics
    stats = {
        "total": queryset.count(),
        "completed": queryset.filter(status="completed").count(),
        "pending": queryset.filter(status__in=["pending", "generating"]).count(),
        "failed": queryset.filter(status="failed").count(),
    }

    # Group reports by year and quarter
    available_years = list(queryset.values_list("year", flat=True).distinct().order_by("-year"))
    reports_by_year = {}
    for yr in available_years:
        year_reports = queryset.filter(year=yr).order_by("-month", "report_type")
        # Group by quarter (Q4 first, Q1 last)
        quarters = {"4": [], "3": [], "2": [], "1": []}
        for report in year_reports:
            quarter = str((report.month - 1) // 3 + 1)
            quarters[quarter].append(report)
        reports_by_year[yr] = quarters

    # 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)

    current_year = datetime.now().year
    years = list(range(current_year, current_year - 5, -1))

    context = {
        "reports_by_year": reports_by_year,
        "filters": request.GET,
        "stats": stats,
        "hospitals": hospitals,
        "years": years,
        "months": [
            (1, _("January")),
            (2, _("February")),
            (3, _("March")),
            (4, _("April")),
            (5, _("May")),
            (6, _("June")),
            (7, _("July")),
            (8, _("August")),
            (9, _("September")),
            (10, _("October")),
            (11, _("November")),
            (12, _("December")),
        ],
        "report_types": KPIReportType.choices,
        "statuses": KPIReportStatus.choices,
    }

    return render(request, "analytics/kpi_report_list.html", context)


@login_required
def kpi_report_detail(request, report_id):
    """
    KPI Report detail view

    Shows the full report with:
    - Excel-style data table
    - Charts (trend and source distribution)
    - Department breakdown
    - PDF export option
    """
    user = request.user

    report = get_object_or_404(KPIReport.objects.select_related("hospital", "generated_by"), id=report_id)

    # Check permissions
    if not user.is_px_admin() and user.hospital != report.hospital:
        messages.error(request, _("You do not have permission to view this report."))
        return redirect("analytics:kpi_report_list")

    # Get monthly data (1-12)
    monthly_data_qs = report.monthly_data.filter(month__gt=0).order_by("month")
    total_data = report.monthly_data.filter(month=0).first()

    # Build monthly data array ensuring 12 months
    monthly_data_dict = {m.month: m for m in monthly_data_qs}
    monthly_data = [monthly_data_dict.get(i) for i in range(1, 13)]

    # Get source breakdowns for pie chart
    source_breakdowns = report.source_breakdowns.all()
    source_chart_data = {
        "labels": [s.source_name for s in source_breakdowns] or ["No Data"],
        "data": [float(s.percentage) for s in source_breakdowns] or [100],
    }

    # Get department breakdowns
    department_breakdowns = report.department_breakdowns.all()

    # Get location breakdowns
    location_breakdowns = report.location_breakdowns.all()

    # Prepare trend chart data - ensure we have 12 values
    trend_data_values = []
    for m in monthly_data:
        if m:
            trend_data_values.append(float(m.percentage))
        else:
            trend_data_values.append(0.0)

    trend_chart_data = {
        "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        "data": trend_data_values,
        "target": float(report.target_percentage) if report.target_percentage else 95.0,
        "threshold": float(report.threshold_percentage) if report.threshold_percentage else 90.0,
    }

    context = {
        "report": report,
        "monthly_data": monthly_data,
        "total_data": total_data,
        "source_breakdowns": source_breakdowns,
        "department_breakdowns": department_breakdowns,
        "location_breakdowns": location_breakdowns,
        "source_chart_data_json": json.dumps(source_chart_data),
        "trend_chart_data_json": json.dumps(trend_chart_data),
    }

    return render(request, "analytics/kpi_report_detail.html", context)


@login_required
def kpi_report_generate(request):
    """
    KPI Report generation form

    Allows manual generation of KPI reports for a specific
    month and hospital.
    """
    user = request.user

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

    current_year = datetime.now().year
    years = list(range(current_year, 2021, -1))

    context = {
        "hospitals": hospitals,
        "years": years,
        "months": [
            (1, _("January")),
            (2, _("February")),
            (3, _("March")),
            (4, _("April")),
            (5, _("May")),
            (6, _("June")),
            (7, _("July")),
            (8, _("August")),
            (9, _("September")),
            (10, _("October")),
            (11, _("November")),
            (12, _("December")),
        ],
        "report_types": KPIReportType.choices,
    }

    return render(request, "analytics/kpi_report_generate.html", context)


@login_required
@require_POST
def kpi_report_generate_submit(request):
    """
    Handle KPI report generation form submission
    """
    user = request.user

    report_type = request.POST.get("report_type")
    hospital_id = request.POST.get("hospital")
    year = request.POST.get("year")
    month = request.POST.get("month")

    # Validation
    if not all([report_type, hospital_id, year, month]):
        if request.headers.get("HX-Request"):
            return render(
                request, "analytics/partials/kpi_generate_error.html", {"error": _("All fields are required.")}
            )
        messages.error(request, _("All fields are required."))
        return redirect("analytics:kpi_report_generate")

    # Check permissions
    try:
        hospital = Hospital.objects.get(id=hospital_id)
    except Hospital.DoesNotExist:
        if request.headers.get("HX-Request"):
            return render(request, "analytics/partials/kpi_generate_error.html", {"error": _("Hospital not found.")})
        messages.error(request, _("Hospital not found."))
        return redirect("analytics:kpi_report_generate")

    if not user.is_px_admin() and user.hospital != hospital:
        if request.headers.get("HX-Request"):
            return render(
                request,
                "analytics/partials/kpi_generate_error.html",
                {"error": _("You do not have permission to generate reports for this hospital.")},
            )
        messages.error(request, _("You do not have permission to generate reports for this hospital."))
        return redirect("analytics:kpi_report_generate")

    try:
        year = int(year)
        month = int(month)

        # Generate the report
        report = KPICalculationService.generate_monthly_report(
            report_type=report_type, hospital=hospital, year=year, month=month, generated_by=user
        )

        success_message = _("KPI Report generated successfully.")

        if request.headers.get("HX-Request"):
            return render(
                request, "analytics/partials/kpi_generate_success.html", {"report": report, "message": success_message}
            )

        messages.success(request, success_message)
        return redirect("analytics:kpi_report_detail", report_id=report.id)

    except Exception as e:
        error_message = str(e)
        if request.headers.get("HX-Request"):
            return render(request, "analytics/partials/kpi_generate_error.html", {"error": error_message})
        messages.error(request, error_message)
        return redirect("analytics:kpi_report_generate")


@login_required
@require_POST
def kpi_report_regenerate(request, report_id):
    """
    Regenerate an existing KPI report
    """
    user = request.user

    report = get_object_or_404(KPIReport, id=report_id)

    # Check permissions
    if not user.is_px_admin() and user.hospital != report.hospital:
        messages.error(request, _("You do not have permission to regenerate this report."))
        return redirect("analytics:kpi_report_list")

    try:
        # Regenerate the report
        KPICalculationService.generate_monthly_report(
            report_type=report.report_type,
            hospital=report.hospital,
            year=report.year,
            month=report.month,
            generated_by=user,
        )

        messages.success(request, _("KPI Report regenerated successfully."))

    except Exception as e:
        messages.error(request, str(e))

    return redirect("analytics:kpi_report_detail", report_id=report.id)


@login_required
def kpi_report_pdf(request, report_id):
    """
    Generate PDF version of KPI report

    Returns HTML page with print-friendly styling and
    html2pdf.js for client-side PDF generation.
    """
    user = request.user

    report = get_object_or_404(KPIReport.objects.select_related("hospital", "generated_by"), id=report_id)

    # Check permissions
    if not user.is_px_admin() and user.hospital != report.hospital:
        messages.error(request, _("You do not have permission to view this report."))
        return redirect("analytics:kpi_report_list")

    # Get monthly data (1-12)
    monthly_data_qs = report.monthly_data.filter(month__gt=0).order_by("month")
    total_data = report.monthly_data.filter(month=0).first()

    # Build monthly data array ensuring 12 months
    monthly_data_dict = {m.month: m for m in monthly_data_qs}
    monthly_data = [monthly_data_dict.get(i) for i in range(1, 13)]

    # Get source breakdowns for pie chart
    source_breakdowns = report.source_breakdowns.all()
    source_chart_data = {
        "labels": [s.source_name for s in source_breakdowns] or ["No Data"],
        "data": [float(s.percentage) for s in source_breakdowns] or [100],
    }

    # Get department breakdowns
    department_breakdowns = report.department_breakdowns.all()

    # Get location breakdowns
    location_breakdowns = report.location_breakdowns.all()

    # Prepare trend chart data - ensure we have 12 values
    trend_data_values = []
    for m in monthly_data:
        if m:
            trend_data_values.append(float(m.percentage))
        else:
            trend_data_values.append(0.0)

    trend_chart_data = {
        "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        "data": trend_data_values,
        "target": float(report.target_percentage) if report.target_percentage else 95.0,
        "threshold": float(report.threshold_percentage) if report.threshold_percentage else 90.0,
    }

    context = {
        "report": report,
        "monthly_data": monthly_data,
        "total_data": total_data,
        "source_breakdowns": source_breakdowns,
        "department_breakdowns": department_breakdowns,
        "location_breakdowns": location_breakdowns,
        "source_chart_data_json": json.dumps(source_chart_data),
        "trend_chart_data_json": json.dumps(trend_chart_data),
        "is_pdf": True,
    }

    return render(request, "analytics/kpi_report_pdf.html", context)


@login_required
def kpi_report_api_data(request, report_id):
    """
    API endpoint for KPI report data (for charts)
    """
    user = request.user

    report = get_object_or_404(KPIReport, id=report_id)

    # Check permissions
    if not user.is_px_admin() and user.hospital != report.hospital:
        return JsonResponse({"error": "Permission denied"}, status=403)

    # Get monthly data
    monthly_data = report.monthly_data.filter(month__gt=0).order_by("month")

    # Get source breakdowns
    source_breakdowns = report.source_breakdowns.all()

    data = {
        "report": {
            "id": str(report.id),
            "type": report.report_type,
            "type_display": report.get_report_type_display(),
            "year": report.year,
            "month": report.month,
            "kpi_id": report.kpi_id,
            "indicator_title": report.indicator_title,
            "target_percentage": float(report.target_percentage),
            "overall_result": float(report.overall_result),
        },
        "monthly_data": [
            {
                "month": m.month,
                "month_name": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][
                    m.month - 1
                ],
                "numerator": m.numerator,
                "denominator": m.denominator,
                "percentage": float(m.percentage),
                "is_below_target": m.is_below_target,
            }
            for m in monthly_data
        ],
        "source_breakdown": [
            {
                "source": s.source_name,
                "count": s.complaint_count,
                "percentage": float(s.percentage),
            }
            for s in source_breakdowns
        ],
    }

    return JsonResponse(data)


@login_required
def kpi_report_ai_analysis(request, report_id):
    """
    Generate or retrieve AI analysis for a KPI report.

    GET: Retrieve existing AI analysis
    POST: Generate new AI analysis
    """
    from django.http import JsonResponse
    from .kpi_service import KPICalculationService

    user = request.user
    report = get_object_or_404(KPIReport.objects.select_related("hospital", "generated_by"), id=report_id)

    # Check permissions
    if not user.is_px_admin() and user.hospital != report.hospital:
        return JsonResponse({"error": "Permission denied"}, status=403)

    if request.method == "GET":
        # Return existing analysis
        if report.ai_analysis:
            return JsonResponse(
                {
                    "success": True,
                    "analysis": report.ai_analysis,
                    "generated_at": report.ai_analysis_generated_at.isoformat()
                    if report.ai_analysis_generated_at
                    else None,
                }
            )
        else:
            return JsonResponse(
                {"success": False, "message": "No AI analysis available. Use POST to generate."}, status=404
            )

    elif request.method == "POST":
        # Generate new analysis
        try:
            analysis = KPICalculationService.generate_ai_analysis(report)

            if "error" in analysis:
                return JsonResponse({"success": False, "error": analysis["error"]}, status=500)

            return JsonResponse(
                {
                    "success": True,
                    "analysis": analysis,
                    "generated_at": report.ai_analysis_generated_at.isoformat()
                    if report.ai_analysis_generated_at
                    else None,
                }
            )

        except Exception as e:
            return JsonResponse({"success": False, "error": str(e)}, status=500)

    return JsonResponse({"error": "Method not allowed"}, status=405)


@login_required
def kpi_report_save_analysis(request, report_id):
    """
    Save edited AI analysis for a KPI report.

    POST: Save edited analysis JSON
    """
    import json
    from django.http import JsonResponse

    user = request.user
    report = get_object_or_404(KPIReport, id=report_id)

    # Check permissions - only PX admins and hospital admins can edit
    if not user.is_px_admin() and user.hospital != report.hospital:
        return JsonResponse({"error": "Permission denied"}, status=403)

    if request.method != "POST":
        return JsonResponse({"error": "Method not allowed"}, status=405)

    try:
        # Parse the edited analysis from request body
        body = json.loads(request.body)
        edited_analysis = body.get("analysis")

        if not edited_analysis:
            return JsonResponse({"error": "No analysis data provided"}, status=400)

        # Preserve metadata if it exists
        if report.ai_analysis and "_metadata" in report.ai_analysis:
            edited_analysis["_metadata"] = report.ai_analysis["_metadata"]
            edited_analysis["_metadata"]["last_edited_at"] = timezone.now().isoformat()
            edited_analysis["_metadata"]["last_edited_by"] = user.get_full_name() or user.email
        else:
            edited_analysis["_metadata"] = {
                "generated_at": timezone.now().isoformat(),
                "report_id": str(report.id),
                "report_type": report.report_type,
                "hospital": report.hospital.name,
                "year": report.year,
                "month": report.month,
                "last_edited_at": timezone.now().isoformat(),
                "last_edited_by": user.get_full_name() or user.email,
            }

        # Save to report
        report.ai_analysis = edited_analysis
        report.save(update_fields=["ai_analysis"])

        logger.info(f"AI analysis edited for KPI report {report.id} by user {user.id}")

        return JsonResponse({"success": True, "message": "Analysis saved successfully"})

    except json.JSONDecodeError:
        return JsonResponse({"error": "Invalid JSON data"}, status=400)
    except Exception as e:
        logger.exception(f"Error saving AI analysis for report {report.id}: {e}")
        return JsonResponse({"error": str(e)}, status=500)
