
from enum import member
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib import messages
from datetime import datetime, timedelta
from django.db.models import Sum, Count, Q, F
from django.urls import reverse
from account.models import *
from django.core.paginator import Paginator
from .utils.decorators import role_required
#for pdf
from django.template.loader import get_template
from django.http import HttpResponse
from xhtml2pdf import pisa

from .variable import gp_marks


import calendar

from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
User = get_user_model()
from .variable import *
from .custom_today import get_custom_today


today = get_custom_today()
current_year = today.year
days_in_year = 366 if calendar.isleap(current_year) else 365
# Get the first date of the current year
first_day_of_year = date(today.year, 1, 1)



def read_apr(request):
    role = request.user.role
    if role and role.modules.filter(name='read_apr_admin').exists():
        aprs = APR.objects.all().order_by('-created_at', '-id')
    elif role and role.modules.filter(name='read_apr_battalion').exists():
        companies = request.user.battalion.companies.all()
        aprs = APR.objects.filter(member__company__in=companies).order_by('-created_at', '-id')
    elif role and role.modules.filter(name='read_apr_company').exists():
        company = request.user.company
        aprs = APR.objects.filter(member__company=company).order_by('-created_at', '-id')
    else:
        return render(request, 'others/no_permission.html')

    
    
    search_query = request.GET.get("search", "")  # Get search query
    if search_query:
        # Use Q objects for OR logic
        aprs = aprs.filter(
            Q(member__army_no__icontains=search_query) |
            Q(member__mobile_no__icontains=search_query) |
            Q(member__name__icontains=search_query)
        )
        
    #get battalion
    battalion_query = request.GET.get('battalion_query', '')
    if battalion_query:
        aprs = aprs.filter(member__company__battalion=battalion_query)
    #get company
    company_query = request.GET.get('company_query', '')
    if company_query:
        aprs = aprs.filter(member__company=company_query)
    
    year = request.GET.get('year', today.year)
    if year:
        aprs = aprs.filter(year=year)
        
        
    # pagination for courseCdrTrg
    paginator = Paginator(aprs, 50)  # 50 records per page
    page_number = request.GET.get('page')
    aprs = paginator.get_page(page_number)
    
    
    # get the current page number with query string
    query_dict = request.GET.copy()
    if 'page' in query_dict:
        query_dict.pop('page')
    query_string = query_dict.urlencode()

    context = {
        "aprs": aprs,
        "search_query": search_query,  # Pass search query to template
        "query_string":query_string,
        "battalions":Battalion.objects.all(),
        "battalion_query":int(battalion_query) if battalion_query else "",
        "company_query":int(company_query) if company_query else "",
        "year":year,
    }
    return render(request, "apr/read_apr.html", context)

def create_apr(request):
    # Get the user's role
    role = request.user.role
    if role and role.modules.filter(name='read_ret_admin').exists():
        members = Member.objects.filter(active=True).order_by('id')
    elif role and role.modules.filter(name='read_ret_battalion').exists():
        companies = request.user.battalion.companies.all()
        members = Member.objects.filter(active=True, company__in=companies).order_by('id')
    elif role and role.modules.filter(name='read_ret_company').exists():
        company = request.user.company
        members = Member.objects.filter(active=True, company=company).order_by('id')
    else:
        return render(request, 'others/no_permission.html')
    

    if request.method == "POST":
        # Handle the form submission
        army_no = request.POST.get("army_no", "")
        year = request.POST.get("year", current_year)
        member = Member.objects.filter(army_no=army_no).first()
        if not member:
            messages.error(request, "Member does not exist.")
            return redirect('create_apr')
        apr = APR.objects.filter(member=member, year=year).exists()
        if apr:
            messages.error(request, "APR already exists.")
            return redirect('create_apr')

        return redirect('save_apr', id=member.id, year=year)
    
    context = {
        'year': year if 'year' in request.POST else current_year,
        'members': members,
    }
    return render(request, "apr/add_apr.html", context)





def save_apr(request,id,year):
    member = Member.objects.get(id=id)
    # Check if the member exists
    role = request.user.role
    if role and role.modules.filter(name='read_apr_admin').exists():
        if not Member.objects.filter(id=member.id).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_battalion').exists():
        companies = request.user.battalion.companies.all()
        if not Member.objects.filter(id=member.id, company__in=companies).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_company').exists():
        company = request.user.company
        if not Member.objects.filter(id=member.id, company=company).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    else:
        return render(request, 'others/no_permission.html')

    # service_info
    service_info, created = ServiceInformation.objects.get_or_create(member=member)

    # punishment/observation/reward
    punishments = Punishment.objects.filter(member=member,date__year=year).order_by('-date', '-id')
    observations = Observation.objects.filter(member=member,date__year=year).order_by('-date', '-id')
    rewards = Reward.objects.filter(member=member,date__year=year).order_by('-date', '-id')

    # course/cdrs
    course_cdrs = Course_Cdr_Trg.objects.filter(Q(leave_type__name="course")|Q(leave_type__name="cdr"),member=member, start_date__year=year).order_by('-start_date', '-id')

    #leave
    total_leaves = Leave.objects.filter(Q(leave_type__name="p_leave")|Q(leave_type__name="c_leave")|Q(leave_type__name="w_leave")|Q(leave_type__name="m_leave")|Q(leave_type__name="j_leave")|Q(leave_type__name="r_leave"),member=member, start_date__year=year).order_by('-start_date', '-id').count()
    total_days = days_in_year - total_leaves

    # performance Record
    priority_order = [1, 0, 2]  # Pass → Exemption → Fail
    # pet history
    pet_1 = None
    for res in priority_order:
        pet_1 = PET.objects.filter(by_annual=1, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if pet_1:
            break
    pet_2 = None
    for res in priority_order:
        pet_2 = PET.objects.filter(by_annual=2, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if pet_2:
            break

    
    # ret history
    ret = None
    ret_score = 0
    for res in priority_order:
        ret = RET.objects.filter(ret=1, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if ret and res == 1:  # Only consider if result is Pass
            # Calculate hit marks (max 15)
            hit_marks = min(ret.hit or 0, 15)  # If None, treat as 0
            # Calculate gp marks
            gp_mark = gp_marks.get(ret.gp, 0)
            # Total score
            ret_score = hit_marks + gp_mark
            break
        if ret:
            break

    # gr_firing history
    gr_firing = None
    for res in priority_order:
        gr_firing = GRFiring.objects.filter(member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if gr_firing:
            break
    gr_firing_score = GRFiring.objects.filter(member=member, date__year=year).aggregate(total_sum=Sum('total'))['total_sum'] or 0

    # fd_firing history
    fd_firing = None
    for res in priority_order:
        fd_firing = FDFiring.objects.filter(member=member, date_from__year=year, result=res).order_by('-date_from', '-id').first()
        if fd_firing:
            break
    # course_shooting history
    course_shooting = None
    for res in priority_order:
        course_shooting = CourseShooting.objects.filter(member=member, date_from__year=year, result=res).order_by('-date_from', '-id').first()
        if course_shooting:
            break

    # sm history
    sm = None
    for res in priority_order:
        sm = SM.objects.filter(member=member, date__year=year, result=res).order_by('-attempt', '-date', '-id').first()
        if sm:
            break

    # aslt_course history
    aslt_course = None
    for res in priority_order:
        aslt_course = AsltCourse.objects.filter(member=member, date__year=year, result=res).order_by('-attempt', '-date', '-id').first()
        if aslt_course:
            break

    traits = [
        ("honour_and_pride", "Honour & Pride"),
        ("honour_and_integrity", "Honour & Integrity"),
        ("loyalty", "Loyalty"),
        ("dutifulness", "Dutifulness"),
        ("courage", "Courage"),
        ("respect", "Respect"),
    ]

    recoms = [
        ("capable_appt", "Is he capable of performing his current appointment independently"),
        ("suitability_for_next_rk", "Is he suitable for promotion to the next rank"),
        ("recom_for_un_msn", "Is he suitable for deployment on overseas mission"),
        ("suitable_for_appt", "Is he suitable for appointment as an instructor"),
    ]

    pen_pictures = [
        ("character_traits", "Character Traits"),
        ("physical_efficiency", "Physical Efficiency"),
        ("firing_efficiency", "Firing Efficiency"),
        ("tactical_efficiency", "Tactical Efficiency"),
        ("technical_efficiency", "Technical Efficiency"),
        ("leadership", "Leadership Ability"),
        ("followership", "Followership Ability"),
        ("comm_skill", "Communication Skill"),
        ("turnout_and_bearing", "Turnout & Bearing"),
        ("appt", "Appt"),
    ]

    context = {
        'member': member,
        'year': year,
        'service_info': service_info,
        "yes_no": Yes_No,
        "opinion": OPINION,
        "punishments": punishments,
        "observations": observations,
        "rewards": rewards,
        "course_cdrs":course_cdrs,
        "total_days": total_days,
        "total_leaves": total_leaves,
        "pet_1": pet_1,
        "pet_2": pet_2,
        "ret": ret,
        "ret_score": ret_score,
        "gr_firing": gr_firing,
        "gr_firing_score": gr_firing_score,
        "fd_firing": fd_firing,
        "course_shooting": course_shooting,
        "sm": sm,
        "aslt_course": aslt_course,
        "states": STATE_LIST,
        "ratings": RATING_LIST,
        "traits": traits,
        "pen_pictures": pen_pictures,
        "recoms": recoms
    }
    if request.method == "POST":
        apr_no = APR.objects.filter(date=today).count() + 1
        
        invoice_number = today.strftime("%d%m%Y") + str(apr_no)
        apr = APR(member=member, year=year)
        apr.date = today  # Set the date to today
        apr.invoice_number = invoice_number
        # part-2
        apr.obesity = request.POST.get("obesity", "")
        apr.sickness = request.POST.get("sickness", "")
        apr.sickness_from = request.POST.get("sickness_from") or None
        apr.sickness_to = request.POST.get("sickness_to") or None
        apr.sickness_remarks = request.POST.get("sickness_remarks", "")
        # Suitability & recommendations
        apr.receive_training = request.POST.get("receive_training", "")
        #part 9
        apr.extra_curricular = request.POST.get("extra_curricular", "")
        apr.advice = request.POST.get("advice", "")

        # Opinion of reported soldier
        apr.opinion_of_reported_sldr = request.POST.get("opinion_of_reported_sldr") or None
        apr.opinion_of_reported_sldr_reason = request.POST.get("opinion_of_reported_sldr_reason", "")
        if apr.opinion_of_reported_sldr == "2" and not apr.opinion_of_reported_sldr_reason.strip():
            messages.error(request, "Please enter a reason for Opinion of Reported Soldier")
            return redirect('save_apr', id=id, year=year)

        # Confirmation by reviewing authority
        apr.cfm_suitability_for_next_rk = request.POST.get("cfm_suitability_for_next_rk") or None
        apr.cfm_suitability_for_next_rk_reason = request.POST.get("cfm_suitability_for_next_rk_reason", "")
        apr.cfm_recom_for_un_msn = request.POST.get("cfm_recom_for_un_msn") or None
        apr.cfm_recom_for_un_msn_reason = request.POST.get("cfm_recom_for_un_msn_reason", "")

        # Final opinion
        apr.opinion = request.POST.get("opinion") or None



        # marks
        apr.marks_physical_efficiency = request.POST.get("marks_physical_efficiency", None)
        apr.marks_firing_efficiency = request.POST.get("marks_firing_efficiency", None)
        apr.marks_tactical_proficiency = request.POST.get("marks_tactical_proficiency", None)
        apr.marks_technical_proficiency = request.POST.get("marks_technical_proficiency", None)
        apr.marks_leadership = request.POST.get("marks_leadership", None)
        apr.marks_followership = request.POST.get("marks_followership", None)
        apr.marks_comm_skill = request.POST.get("marks_comm_skill", None)
        apr.marks_turnout_and_bearing = request.POST.get("marks_turnout_and_bearing", None)
        apr.marks_appt = request.POST.get("marks_appt", None)

        apr.marks_character_traits = request.POST.get("marks_character_traits", None)
        apr.marks_discipline = request.POST.get("marks_discipline", None)
        apr.marks_course_cdr = request.POST.get("marks_course_cdr", None)
        apr.marks_award = request.POST.get("marks_award", None)

        #part 3
        for i in range(1, 6):  # for 5 rows
            resp = request.POST.get(f"part_3_resp_{i}", "")
            from_date = request.POST.get(f"part_3_from_{i}") or None
            to_date = request.POST.get(f"part_3_to_{i}") or None
            imm_reporting = request.POST.get(f"part_3_imm_reporting_{i}", "")
            unit = request.POST.get(f"part_3_unit_{i}", "")
            reporting_offr = request.POST.get(f"part_3_reporting_offr_{i}", "")

            setattr(apr, f"part_3_resp_{i}", resp)
            setattr(apr, f"part_3_from_{i}", from_date)
            setattr(apr, f"part_3_to_{i}", to_date)
            setattr(apr, f"part_3_unit_{i}", unit)
            setattr(apr, f"part_3_imm_reporting_{i}", imm_reporting)
            setattr(apr, f"part_3_reporting_offr_{i}", reporting_offr)
            duration = None
            if from_date and to_date:
                from_dt = datetime.strptime(from_date, "%Y-%m-%d").date()
                to_dt = datetime.strptime(to_date, "%Y-%m-%d").date()
                duration = (to_dt - from_dt).days + 1
            setattr(apr, f"part_3_duration_{i}", duration)

        #spl contribution
        for i in range(1, 6):  # for 5 rows
            contribution = request.POST.get(f"spl_contribution_{i}", "")
            from_date = request.POST.get(f"spl_from_{i}") or None
            to_date = request.POST.get(f"spl_to_{i}") or None
            role = request.POST.get(f"spl_role_{i}", "")
            performance = request.POST.get(f"spl_performance_{i}", "")

            setattr(apr, f"spl_contribution_{i}", contribution)
            setattr(apr, f"spl_from_{i}", from_date)
            setattr(apr, f"spl_to_{i}", to_date)
            setattr(apr, f"spl_role_{i}", role)
            setattr(apr, f"spl_performance_{i}", performance)
            duration = None
            if from_date and to_date:
                from_dt = datetime.strptime(from_date, "%Y-%m-%d").date()
                to_dt = datetime.strptime(to_date, "%Y-%m-%d").date()
                duration = (to_dt - from_dt).days + 1
            setattr(apr, f"spl_duration_{i}", duration)
        #ops activities
        for i in range(1, 6):  # for 5 rows
            activities = request.POST.get(f"ops_activities_{i}", "")
            from_date = request.POST.get(f"ops_from_{i}") or None
            to_date = request.POST.get(f"ops_to_{i}") or None
            role = request.POST.get(f"ops_role_{i}", "")
            performance = request.POST.get(f"ops_performance_{i}", "")

            setattr(apr, f"ops_activities_{i}", activities)
            setattr(apr, f"ops_from_{i}", from_date)
            setattr(apr, f"ops_to_{i}", to_date)
            setattr(apr, f"ops_role_{i}", role)
            setattr(apr, f"ops_performance_{i}", performance)
            duration = None
            if from_date and to_date:
                from_dt = datetime.strptime(from_date, "%Y-%m-%d").date()
                to_dt = datetime.strptime(to_date, "%Y-%m-%d").date()
                duration = (to_dt - from_dt).days + 1
            setattr(apr, f"ops_duration_{i}", duration)
        #trg activities
        for i in range(1, 6):  # for 5 rows
            activities = request.POST.get(f"trg_activities_{i}", "")
            from_date = request.POST.get(f"trg_from_{i}") or None
            to_date = request.POST.get(f"trg_to_{i}") or None
            role = request.POST.get(f"trg_role_{i}", "")
            performance = request.POST.get(f"trg_performance_{i}", "")

            setattr(apr, f"trg_activities_{i}", activities)
            setattr(apr, f"trg_from_{i}", from_date)
            setattr(apr, f"trg_to_{i}", to_date)
            setattr(apr, f"trg_role_{i}", role)
            setattr(apr, f"trg_performance_{i}", performance)
            duration = None
            if from_date and to_date:
                from_dt = datetime.strptime(from_date, "%Y-%m-%d").date()
                to_dt = datetime.strptime(to_date, "%Y-%m-%d").date()
                duration = (to_dt - from_dt).days + 1
            setattr(apr, f"trg_duration_{i}", duration)
        #admin activities
        for i in range(1, 6):  # for 5 rows
            activities = request.POST.get(f"admin_activities_{i}", "")
            from_date = request.POST.get(f"admin_from_{i}") or None
            to_date = request.POST.get(f"admin_to_{i}") or None
            role = request.POST.get(f"admin_role_{i}", "")
            performance = request.POST.get(f"admin_performance_{i}", "")

            setattr(apr, f"admin_activities_{i}", activities)
            setattr(apr, f"admin_from_{i}", from_date)
            setattr(apr, f"admin_to_{i}", to_date)
            setattr(apr, f"admin_role_{i}", role)
            setattr(apr, f"admin_performance_{i}", performance)
            duration = None
            if from_date and to_date:
                from_dt = datetime.strptime(from_date, "%Y-%m-%d").date()
                to_dt = datetime.strptime(to_date, "%Y-%m-%d").date()
                duration = (to_dt - from_dt).days + 1
            setattr(apr, f"admin_duration_{i}", duration)


        for trait in traits:
            for field in ["state", "reason", "reference"]:
                setattr(apr, f"{trait[0]}_{field}", request.POST.get(f"{trait[0]}_{field}", ""))
        
        for i in pen_pictures:
            setattr(apr, f"{i[0]}", request.POST.get(f"{i[0]}", None))

        for field, _ in recoms:
            value = request.POST.get(field, "")
            reason = request.POST.get(f"{field}_reason", "")
            # Save values temporarily
            setattr(apr, field, value)
            setattr(apr, f"{field}_reason", reason)
            # ✅ Backend validation: reason is required if value == "2"
            if value == "2" and not reason.strip():
                messages.error(request, f"Please enter a reason for {field}")
                return redirect('save_apr', id=id, year=year)


        apr.save()

        # Process the APR data here
        # For example, save it to the database or perform calculations

        messages.success(request, "APR saved successfully.")
        return redirect('read_apr')
    return render(request, "apr/save_apr.html", context)


def delete_apr(request, id):
    apr = APR.objects.get(id=id)
    member = apr.member
    # Check if the member exists
    role = request.user.role
    if role and role.modules.filter(name='read_apr_admin').exists():
        if not Member.objects.filter(id=member.id).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_battalion').exists():
        companies = request.user.battalion.companies.all()
        if not Member.objects.filter(id=member.id, company__in=companies).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_company').exists():
        company = request.user.company
        if not Member.objects.filter(id=member.id, company=company).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    else:
        return render(request, 'others/no_permission.html')
    # delete apr
    apr.delete()
    messages.success(request, "APR deleted successfully.")
    return redirect('read_apr')


def read_apr_pdf(request, id):
    apr = APR.objects.get(id=id)
    member = apr.member
    year = apr.year
    today = apr.date
    heading_date = None

     # Check if the member exists
    role = request.user.role
    if role and role.modules.filter(name='read_apr_admin').exists():
        if not Member.objects.filter(id=member.id).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_battalion').exists():
        companies = request.user.battalion.companies.all()
        if not Member.objects.filter(id=member.id, company__in=companies).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    elif role and role.modules.filter(name='read_apr_company').exists():
        company = request.user.company
        if not Member.objects.filter(id=member.id, company=company).exists():
            messages.error(request, "Member does not exist")
            return redirect('read_apr')
    else:
        return render(request, 'others/no_permission.html')
    
    
    # performance Record
    priority_order = [1, 0, 2]  # Pass → Exemption → Fail
    # pet history
    pet_1 = None
    for res in priority_order:
        pet_1 = PET.objects.filter(by_annual=1, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if pet_1:
            break
    pet_2 = None
    for res in priority_order:
        pet_2 = PET.objects.filter(by_annual=2, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if pet_2:
            break

    # ret history
    ret = None
    for res in priority_order:
        ret = RET.objects.filter(ret=1, member=member, date__year=year, result=res).order_by('-date', '-id').first()
        if ret and res == 1:  # Only consider if result is Pass
            # Calculate hit marks (max 15)
            hit_marks = min(ret.hit or 0, 15)  # If None, treat as 0
            # Calculate gp marks
            gp_mark = gp_marks.get(ret.gp, 0)
            # Total score
            ret_score = hit_marks + gp_mark
            break
        if ret:
            break

    traits = [
        ("honour_and_pride", "Honour & Pride"),
        ("honour_and_integrity", "Honour & Integrity"),
        ("loyalty", "Loyalty"),
        ("dutifulness", "Dutifulness"),
        ("courage", "Courage"),
        ("respect", "Respect"),
    ]
    trait_data = []
    for key, label in traits:
        display_method = f"get_{key}_state_display"
        trait_data.append({
            "label": label,
            "state": getattr(apr, display_method)() if hasattr(apr, display_method) else "",
            "reason": getattr(apr, f"{key}_reason"),
            "reference": getattr(apr, f"{key}_reference"),
        })



    pen_pictures = [
        ("character_traits", "Character Traits"),
        ("physical_efficiency", "Physical Efficiency"),
        ("firing_efficiency", "Firing Efficiency"),
        ("tactical_efficiency", "Tactical Efficiency"),
        ("technical_efficiency", "Technical Efficiency"),
        ("leadership", "Leadership Ability"),
        ("followership", "Followership Ability"),
        ("comm_skill", "Communication Skill"),
        ("turnout_and_bearing", "Turnout & Bearing"),
        ("appt", "Appt"),
    ]

    pen_picture_data = []
    for key, label in pen_pictures:
        display_method = f"get_{key}_display"
        pen_picture_data.append({
            "label": label,
            "state": getattr(apr, display_method)() if hasattr(apr, display_method) else "",
        })



    spl_contribution = []
    for i in range(1, 6):  # since you have 1 to 5
        spl_contribution.append({
            "spl": getattr(apr, f"spl_contribution_{i}"),
        })

    part3_data = []
    for i in range(1, 6):  # since you have 1 to 5
        part3_data.append({
            "resp": getattr(apr, f"part_3_resp_{i}"),
            "from": getattr(apr, f"part_3_from_{i}"),
            "to": getattr(apr, f"part_3_to_{i}"),
            "duration": getattr(apr, f"part_3_duration_{i}"),
            "unit": getattr(apr, f"part_3_unit_{i}"),
            "imm_reporting": getattr(apr, f"part_3_imm_reporting_{i}"),
            "reporting_offr": getattr(apr, f"part_3_reporting_offr_{i}"),
        })

    # punishment/observation/reward
    punishments = Punishment.objects.filter(member=member,date__year=year).order_by('-date', '-id')
    punishment_count = punishments.count()
    observations = Observation.objects.filter(member=member,date__year=year).order_by('-date', '-id')
    rewards = Reward.objects.filter(member=member,date__year=year).order_by('-date', '-id')
    reward_count = rewards.count()

    # course/cdrs
    course_cdrs = Course_Cdr_Trg.objects.filter(Q(leave_type__name="course")|Q(leave_type__name="cdr"),member=member, start_date__year=year).order_by('-start_date', '-id')

    #leave
    total_leaves = Leave.objects.filter(Q(leave_type__name="p_leave")|Q(leave_type__name="c_leave")|Q(leave_type__name="w_leave")|Q(leave_type__name="m_leave")|Q(leave_type__name="j_leave")|Q(leave_type__name="r_leave"),member=member, start_date__year=year).order_by('-start_date', '-id').count()
    total_days = days_in_year - total_leaves
    # Calculate the difference in days
    if year == today.year:
        days_passed = (today - first_day_of_year).days + 1  # +1 to include today
        total_days = days_passed - total_leaves
        heading_date = today.strftime("%d %B %Y")

    total_marks = apr.marks_physical_efficiency + apr.marks_firing_efficiency + apr.marks_tactical_proficiency + apr.marks_technical_proficiency + apr.marks_leadership + apr.marks_followership + apr.marks_comm_skill + apr.marks_turnout_and_bearing + apr.marks_appt

    grand_total_marks = total_marks + apr.marks_character_traits + apr.marks_discipline + apr.marks_course_cdr + apr.marks_award

    def get_grade(score):
        if 91 <= score <= 100:
            return "Outstanding"
        elif 81 <= score <= 90:
            return "Above Average"
        elif 66 <= score <= 80:
            return "Average"
        elif 50 <= score <= 65:
            return "Below Average"
        elif 0 <= score <= 49:
            return "Poor"
        return "Invalid"
    grade = get_grade(grand_total_marks)
    context = {
        "apr": apr,
        "pet_1": pet_1,
        "pet_2": pet_2,
        "ret": ret,
        "part3_data": part3_data,
        "punishments": punishments,
        "punishment_count": punishment_count,
        "observations": observations,
        "rewards": rewards,
        "reward_count": reward_count,
        "spl_contribution": spl_contribution,
        "course_cdrs": course_cdrs,
        "total_leaves": total_leaves,
        "total_days": total_days,
        "total_marks": total_marks,
        "grand_total_marks": grand_total_marks,
        "trait_data": trait_data,
        "pen_picture_data": pen_picture_data,
        "grade": grade,
        "heading_date": heading_date,
        "invoice_number": apr.invoice_number
    }
    # Load the HTML template and render it with context data
    template = get_template('apr/read_apr_pdf.html')
    html = template.render(context)

    # Create a response with PDF content type
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = f'inline; filename="APR_{apr.member.rank.name}_{apr.member.army_no}_{apr.member.name}_{apr.year}_{apr.invoice_number}.pdf"'

    # Convert HTML to PDF
    pisa_status = pisa.CreatePDF(html, dest=response)

    if pisa_status.err:
        return HttpResponse("Error generating PDF", status=500)
    
    return response