"""
Vistas — App Reports
======================
Generación y descarga de PDFs:
1. Factura individual (paciente, doctora, admin)
2. Reporte diario de citas (doctora, admin)
3. Reporte mensual financiero (admin)
"""

import logging
from datetime import date
from decimal import Decimal

from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.db.models import Count, Sum
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone

from apps.users.decorators import admin_required, moderador_required

from .pdf_generator import (
    generar_factura_pdf,
    generar_reporte_anual_pdf,
    generar_reporte_diario_pdf,
    generar_reporte_mensual_pdf,
)

logger = logging.getLogger("apps.reports")


# ============================================================
# 1. FACTURA INDIVIDUAL PDF
# ============================================================
@login_required
def factura_pdf(request, factura_id):
    """
    Descarga PDF de una factura individual.
    - Paciente: solo sus propias facturas.
    - Doctora/Admin: cualquier factura.
    """
    from apps.finance.models import Invoice

    invoice = get_object_or_404(
        Invoice.objects.select_related("paciente", "servicio", "cita", "clinica"),
        id=factura_id,
        is_active=True,
    )

    # Control de acceso: paciente solo ve sus facturas
    user = request.user
    if user.rol == "paciente" and invoice.paciente_id != user.id:
        logger.warning(
            "Acceso denegado: %s intentó descargar factura %s de otro paciente",
            user.email,
            invoice.numero,
        )
        raise PermissionDenied("No tienes permiso para ver esta factura.")

    pdf_bytes = generar_factura_pdf(invoice)

    response = HttpResponse(pdf_bytes, content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="{invoice.numero}.pdf"'
    logger.info("PDF factura descargado: %s por %s", invoice.numero, user.email)
    return response


# ============================================================
# 2. REPORTE DIARIO DE CITAS PDF
# ============================================================
@moderador_required
def reporte_diario_pdf(request):
    """
    Descarga PDF del reporte diario de citas.
    Parámetro GET ?fecha=YYYY-MM-DD (default: hoy).
    """
    from apps.appointments.models import Cita
    from apps.finance.models import Invoice

    fecha_str = request.GET.get("fecha")
    if fecha_str:
        try:
            fecha = date.fromisoformat(fecha_str)
        except (ValueError, TypeError):
            fecha = timezone.now().date()
    else:
        fecha = timezone.now().date()

    citas = list(
        Cita.objects.filter(
            fecha_hora__date=fecha,
            is_active=True,
        )
        .select_related("paciente", "servicio")
        .order_by("fecha_hora")
    )

    ingresos_dia = (
        Invoice.objects.filter(
            fecha_emision__date=fecha,
            is_active=True,
        )
        .exclude(estado=Invoice.Estado.ANULADO)
        .aggregate(total=Sum("total"))["total"]
        or Decimal("0.00")
    )

    pdf_bytes = generar_reporte_diario_pdf(fecha, citas, ingresos_dia)

    filename = f"reporte_diario_{fecha.strftime('%Y%m%d')}.pdf"
    response = HttpResponse(pdf_bytes, content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="{filename}"'
    logger.info("PDF reporte diario descargado: %s por %s", fecha, request.user.email)
    return response


# ============================================================
# 3. REPORTE MENSUAL FINANCIERO PDF
# ============================================================
@moderador_required
def reporte_mensual_pdf(request):
    """
    Descarga PDF del reporte financiero mensual.
    Agrupa ingresos por clínica con totales de precio_venta, porciento_medico, IRT e ingreso neto.
    Parámetros GET ?year=YYYY&month=MM (default: mes actual).
    """
    from apps.finance.models import FacturaDia, Clinica

    hoy = timezone.now().date()
    try:
        year = int(request.GET.get("year", hoy.year))
        month = int(request.GET.get("month", hoy.month))
        if not (1 <= month <= 12) or not (2020 <= year <= 2099):
            raise ValueError
    except (ValueError, TypeError):
        year, month = hoy.year, hoy.month

    facturas = (
        FacturaDia.objects.filter(
            fecha__year=year,
            fecha__month=month,
            is_active=True,
        )
        .exclude(estado=FacturaDia.Estado.ANULADA)
        .select_related("clinica")
    )

    # Agrupar por clínica
    from django.db.models import F
    clinica_stats = list(
        facturas.values(clinica_nombre=F("clinica__nombre"))
        .annotate(
            total_pventa=Sum("precio_venta_total"),
            total_medico=Sum("porciento_medico_total"),
            num_facturas=Count("id"),
        )
        .order_by("clinica_nombre")
    )

    # Calcular IRT e ingreso neto por clínica (no se pueden agregar propiedades en annotate)
    for stat in clinica_stats:
        pventa = stat["total_pventa"] or Decimal("0")
        medico = stat["total_medico"] or Decimal("0")
        # IRT: sumar los montos IRT de cada factura de esta clínica
        clinica_facturas = facturas.filter(clinica__nombre=stat["clinica_nombre"])
        irt_total = Decimal("0")
        neto_total = Decimal("0")
        for f in clinica_facturas:
            irt_total += f.irt_monto
            neto_total += f.ingreso_neto
        stat["total_pventa"] = pventa
        stat["total_medico"] = medico
        stat["total_irt"] = irt_total
        stat["total_neto"] = neto_total

    # Totales generales
    grand = {
        "total_pventa": sum(s["total_pventa"] for s in clinica_stats),
        "total_medico": sum(s["total_medico"] for s in clinica_stats),
        "total_irt": sum(s["total_irt"] for s in clinica_stats),
        "total_neto": sum(s["total_neto"] for s in clinica_stats),
        "num_facturas": sum(s["num_facturas"] for s in clinica_stats),
    }

    pdf_bytes = generar_reporte_mensual_pdf(year, month, clinica_stats, grand)

    filename = f"reporte_financiero_{year}_{month:02d}.pdf"
    response = HttpResponse(pdf_bytes, content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="{filename}"'
    logger.info("PDF reporte mensual descargado: %s-%02d por %s", year, month, request.user.email)
    return response


# ============================================================
# 4. REPORTE ANUAL FINANCIERO PDF
# ============================================================
@moderador_required
def reporte_anual_pdf(request):
    """
    Descarga PDF del reporte financiero anual (12 meses, landscape).
    Parámetro GET ?year=YYYY (default: año actual).
    """
    from apps.finance.models import FacturaDia

    hoy = timezone.now().date()
    try:
        year = int(request.GET.get("year", hoy.year))
        if not (2020 <= year <= 2099):
            raise ValueError
    except (ValueError, TypeError):
        year = hoy.year

    facturas = list(
        FacturaDia.objects.filter(
            fecha__year=year,
            is_active=True,
        )
        .exclude(estado=FacturaDia.Estado.ANULADA)
        .select_related("clinica")
    )

    # Obtener clínicas que tienen facturas
    clinica_nombres = sorted(set(
        f.clinica.nombre for f in facturas if f.clinica
    ))

    meses_data = []
    for cname in clinica_nombres:
        clinica_info = {
            "nombre": cname,
            "meses": {},
            "total_pventa": Decimal("0"),
            "total_medico": Decimal("0"),
            "total_irt": Decimal("0"),
            "total_neto": Decimal("0"),
        }
        clinica_facturas = [f for f in facturas if f.clinica and f.clinica.nombre == cname]
        for f in clinica_facturas:
            m = f.fecha.month
            if m not in clinica_info["meses"]:
                clinica_info["meses"][m] = {"pventa": Decimal("0"), "medico": Decimal("0"), "irt": Decimal("0"), "neto": Decimal("0")}
            clinica_info["meses"][m]["pventa"] += f.precio_venta_total
            clinica_info["meses"][m]["medico"] += f.porciento_medico_total
            clinica_info["meses"][m]["irt"] += f.irt_monto
            clinica_info["meses"][m]["neto"] += f.ingreso_neto
            clinica_info["total_pventa"] += f.precio_venta_total
            clinica_info["total_medico"] += f.porciento_medico_total
            clinica_info["total_irt"] += f.irt_monto
            clinica_info["total_neto"] += f.ingreso_neto
        meses_data.append(clinica_info)

    # Grand totals por mes
    grand = {
        "meses": {},
        "total_pventa": Decimal("0"),
        "total_medico": Decimal("0"),
        "total_irt": Decimal("0"),
        "total_neto": Decimal("0"),
    }
    for clinica in meses_data:
        for m, vals in clinica["meses"].items():
            if m not in grand["meses"]:
                grand["meses"][m] = {"pventa": Decimal("0"), "medico": Decimal("0"), "irt": Decimal("0"), "neto": Decimal("0")}
            for key in ("pventa", "medico", "irt", "neto"):
                grand["meses"][m][key] += vals[key]
        grand["total_pventa"] += clinica["total_pventa"]
        grand["total_medico"] += clinica["total_medico"]
        grand["total_irt"] += clinica["total_irt"]
        grand["total_neto"] += clinica["total_neto"]

    pdf_bytes = generar_reporte_anual_pdf(year, meses_data, grand)

    filename = f"reporte_anual_{year}.pdf"
    response = HttpResponse(pdf_bytes, content_type="application/pdf")
    response["Content-Disposition"] = f'attachment; filename="{filename}"'
    logger.info("PDF reporte anual descargado: %s por %s", year, request.user.email)
    return response
