"""
academics/views_report_cards.py

Views for:
  1. Browser preview (HTML)
  2. Single student PDF download
  3. Bulk class PDF download
  4. REST API endpoint (returns PDF as file response)

Wire up in academics/urls.py:
    from academics.views_report_cards import (
        report_card_preview,
        report_card_pdf_download,
        bulk_class_pdf_download,
        ReportCardAPIView,
        BulkReportCardAPIView,
    )
    urlpatterns = [
        path('report-card/<int:pk>/preview/',   report_card_preview,        name='rc-preview'),
        path('report-card/<int:pk>/pdf/',       report_card_pdf_download,   name='rc-pdf'),
        path('report-card/bulk/<int:class_id>/<int:term_id>/',
                                                bulk_class_pdf_download,    name='rc-bulk'),
        # REST
        path('api/report-cards/<int:pk>/pdf/', ReportCardAPIView.as_view(),   name='rc-api-pdf'),
        path('api/report-cards/bulk/',          BulkReportCardAPIView.as_view(), name='rc-api-bulk'),
    ]
"""

import logging
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.decorators import method_decorator
from django.views import View
from django.template.loader import render_to_string

from academics.models_grades import ReportCard, AcademicTerm
from academics.models import SchoolClass
from academics.report_card_generator import (
    generate_report_card_pdf,
    generate_bulk_pdf,
    build_report_card_context,
    TEMPLATE_MAP,
    _resolve_report_type,
)

logger = logging.getLogger(__name__)


# ─────────────────────────────────────────────────────────────
# 1. HTML BROWSER PREVIEW  (no PDF library needed)
# ─────────────────────────────────────────────────────────────

@login_required
def report_card_preview(request, pk):
    """
    Render the report card as HTML in the browser.
    Useful for checking layout before generating a PDF.

    URL: /report-card/<pk>/preview/
    """
    rc = get_object_or_404(ReportCard, pk=pk)
    _check_access(request.user, rc)

    template_name = TEMPLATE_MAP.get(rc.report_type)
    context = build_report_card_context(rc)
    return render(request, template_name, context)


# ─────────────────────────────────────────────────────────────
# 2. SINGLE STUDENT PDF DOWNLOAD
# ─────────────────────────────────────────────────────────────

@login_required
def report_card_pdf_download(request, pk):
    """
    Generate and stream a PDF for one student's report card.

    URL: /report-card/<pk>/pdf/
    Query params:
        ?save=1   — also save the PDF file to the model (default: 0)
        ?force=1  — regenerate even if PDF already exists
    """
    rc = get_object_or_404(ReportCard, pk=pk)
    _check_access(request.user, rc)

    save = request.GET.get('save', '0') == '1'
    force = request.GET.get('force', '0') == '1'

    # Return cached PDF unless forced
    if rc.pdf_file and not force:
        try:
            response = HttpResponse(rc.pdf_file.read(), content_type='application/pdf')
            response['Content-Disposition'] = (
                f'attachment; filename="{_pdf_filename(rc)}"'
            )
            return response
        except Exception:
            pass  # Fall through to regenerate

    try:
        pdf_bytes = generate_report_card_pdf(rc, save_to_model=save)
    except ImportError as e:
        return JsonResponse({'error': str(e)}, status=500)
    except Exception as e:
        logger.exception("Report card generation failed for RC %s", pk)
        return JsonResponse({'error': str(e)}, status=500)

    response = HttpResponse(pdf_bytes, content_type='application/pdf')
    response['Content-Disposition'] = (
        f'attachment; filename="{_pdf_filename(rc)}"'
    )
    return response


# ─────────────────────────────────────────────────────────────
# 3. BULK CLASS PDF DOWNLOAD
# ─────────────────────────────────────────────────────────────

@login_required
def bulk_class_pdf_download(request, class_id, term_id):
    """
    Generate one merged PDF containing all students' report cards
    for a class in a given term.

    URL: /report-card/bulk/<class_id>/<term_id>/
    """
    school_class = get_object_or_404(SchoolClass, pk=class_id)
    term = get_object_or_404(AcademicTerm, pk=term_id)

    if not _user_can_access_class(request.user, school_class):
        return HttpResponse('Forbidden', status=403)

    try:
        pdf_bytes = generate_bulk_pdf(school_class, term)
    except ValueError as e:
        return JsonResponse({'error': str(e)}, status=400)
    except ImportError as e:
        return JsonResponse({'error': str(e)}, status=500)
    except Exception as e:
        logger.exception("Bulk PDF generation failed for class %s term %s", class_id, term_id)
        return JsonResponse({'error': str(e)}, status=500)

    filename = (
        f"BulkRC_{school_class.code}_"
        f"T{term.term}_{term.academic_year.replace('-','_')}.pdf"
    )
    response = HttpResponse(pdf_bytes, content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="{filename}"'
    return response


# ─────────────────────────────────────────────────────────────
# 4. REST API VIEWS (for frontend / mobile apps)
# ─────────────────────────────────────────────────────────────

class ReportCardAPIView(View):
    """
    GET /api/report-cards/<pk>/pdf/
    Returns the PDF for a single student's report card.

    Requires: Authorization header or session login.
    """

    @method_decorator(login_required)
    def get(self, request, pk):
        rc = get_object_or_404(ReportCard, pk=pk)
        _check_access(request.user, rc)
        try:
            pdf_bytes = generate_report_card_pdf(rc, save_to_model=False)
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)

        response = HttpResponse(pdf_bytes, content_type='application/pdf')
        response['Content-Disposition'] = (
            f'inline; filename="{_pdf_filename(rc)}"'
        )
        return response


class BulkReportCardAPIView(View):
    """
    POST /api/report-cards/bulk/
    Body: { "class_id": <int>, "term_id": <int> }
    Returns merged PDF for the entire class.
    """

    @method_decorator(login_required)
    def post(self, request):
        import json
        try:
            data = json.loads(request.body)
            class_id = int(data['class_id'])
            term_id  = int(data['term_id'])
        except (KeyError, ValueError, json.JSONDecodeError) as e:
            return JsonResponse({'error': f'Invalid request: {e}'}, status=400)

        school_class = get_object_or_404(SchoolClass, pk=class_id)
        term = get_object_or_404(AcademicTerm, pk=term_id)

        if not _user_can_access_class(request.user, school_class):
            return JsonResponse({'error': 'Forbidden'}, status=403)

        try:
            pdf_bytes = generate_bulk_pdf(school_class, term)
        except ValueError as e:
            return JsonResponse({'error': str(e)}, status=400)
        except Exception as e:
            logger.exception("Bulk PDF via API failed")
            return JsonResponse({'error': str(e)}, status=500)

        filename = (
            f"BulkRC_{school_class.code}_"
            f"T{term.term}_{term.academic_year.replace('-','_')}.pdf"
        )
        response = HttpResponse(pdf_bytes, content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        return response


# ─────────────────────────────────────────────────────────────
# 5. ADMIN ACTION: generate all report cards for a class
# ─────────────────────────────────────────────────────────────

def admin_generate_class_report_cards(modeladmin, request, queryset):
    """
    Django admin action: generate PDFs for selected ReportCard objects.
    Add to ReportCardAdmin:
        actions = [admin_generate_class_report_cards]
    """
    generated = 0
    errors = []
    for rc in queryset:
        try:
            generate_report_card_pdf(rc, save_to_model=True)
            generated += 1
        except Exception as e:
            errors.append(f"{rc}: {e}")

    msg = f"Generated {generated} PDF(s)."
    if errors:
        msg += f" Errors: {'; '.join(errors)}"
    modeladmin.message_user(request, msg)


admin_generate_class_report_cards.short_description = "Generate PDF report cards"


# ─────────────────────────────────────────────────────────────
# Helpers
# ─────────────────────────────────────────────────────────────

def _pdf_filename(rc):
    return (
        f"ReportCard_{rc.student.student_id}_"
        f"{rc.get_report_type_display().replace(' ','_')}_"
        f"T{rc.term.term}_{rc.term.academic_year.replace('-','_')}.pdf"
    )


def _check_access(user, report_card):
    """Raise 403 if user cannot access this report card."""
    if user.user_type in ('super_admin', 'proprietor', 'school_admin',
                          'head_master', 'head_mistress', 'bursar',
                          'teacher', 'class_teacher'):
        return
    # Parent: can only access their own child's card
    if user.user_type == 'parent':
        student_ids = user.students_as_parent.values_list('id', flat=True) \
                      if hasattr(user, 'students_as_parent') else []
        if report_card.student_id not in student_ids:
            from django.core.exceptions import PermissionDenied
            raise PermissionDenied
    return


def _user_can_access_class(user, school_class):
    if user.user_type in ('super_admin', 'proprietor', 'school_admin',
                          'head_master', 'head_mistress', 'bursar'):
        return True
    if user.user_type in ('teacher', 'class_teacher'):
        try:
            return user.staff_profile.homeroom_class == school_class
        except Exception:
            return False
    return False
