
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib import messages
from account.models import *
from itertools import groupby
from datetime import datetime
from datetime import timedelta
from dateutil.relativedelta import relativedelta
from django.contrib.auth import get_user_model
from django.core.paginator import Paginator
from django.db.models import Q
from .custom_today import get_custom_today
from .utils.decorators import role_required
import calendar



User = get_user_model()
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)
day_count = (today - first_day_of_year).days + 1
#member dashboard    
@role_required('dashboard_member')
def dashboard_member(request):
    member = request.user.member
    notices = Notice.objects.filter(member=member).order_by('-date')
    notice_count = notices.filter(date=today).count()
    # Pagination
    paginator = Paginator(notices, 20)  # Show 20 notices per page
    page_number = request.GET.get("page")
    notices = paginator.get_page(page_number)

    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=current_year).order_by('-start_date', '-id').count()
    total_days = day_count - total_leaves

    # punishment/observation/reward
    punishment_count = Punishment.objects.filter(member=member).order_by('-date', '-id').count()
    observation_count = Observation.objects.filter(member=member).order_by('-date', '-id').count()
    reward_count = Reward.objects.filter(member=member).order_by('-date', '-id').count()
    spl_qual_count = SpecialQualityInformation.objects.filter(member=member).order_by('-id').count()




    # collect events
    events = []

    # Main Leaves (red)
    for leave in MainLeave.objects.filter(member=member):
        events.append({
            "title": str(leave.leave_type.showName),
            "start": leave.start_date.isoformat(),
            "end": (leave.end_date + timedelta(days=1)).isoformat(),  # fullcalendar is exclusive
            "color": "red"
        })

    # Ops Deployment (green)
    for depl in OpsDepl.objects.filter(member=member):
        end = depl.end_date if depl.end_date else date.today()
        events.append({
            "title": "Ops Depl",
            "start": depl.start_date.isoformat(),
            "end": (end + timedelta(days=1)).isoformat(),
            "color": "green"
        })

    # Courses (blue)
    for course in Course_Cdr_Trg.objects.filter(member=member):
        events.append({
            "title": str(course.course_name),
            "start": course.start_date.isoformat(),
            "end": (course.end_date + timedelta(days=1)).isoformat(),
            "color": "blue"
        })

    # Out of Unit (orange)
    for out in OutOfUnitEmp.objects.filter(member=member):
        end = out.end_date if out.end_date else date.today()
        events.append({
            "title": out.get_type_name_display(),
            "start": out.start_date.isoformat(),
            "end": (end + timedelta(days=1)).isoformat(),
            "color": "orange"
        })

    # Unauth Absents (purple)
    for absent in UnauthAbsent.objects.filter(member=member):
        end = absent.end_date if absent.end_date else date.today()
        events.append({
            "title": str(absent.leave_type.showName),
            "start": absent.start_date.isoformat(),
            "end": (end + timedelta(days=1)).isoformat(),
            "color": "purple"
        })

    # Other reasons (brown)
    for other in OtherReason.objects.filter(member=member):
        end = other.end_date if other.end_date else date.today()
        events.append({
            "title": str(other.leave_type.showName),
            "start": other.start_date.isoformat(),
            "end": (end + timedelta(days=1)).isoformat(),
            "color": "brown"
        })


    context = {
        "notices": notices,
        "notice_count": notice_count,
        "leave_count": total_leaves,
        "days_count": total_days,
        "punishment_count": punishment_count,
        "observation_count": observation_count,
        "reward_count": reward_count,
        "spl_qual_count": spl_qual_count,
        "events": events
    }

    return render(request,"dashboard/dashboard_member.html",context)


def memberProfile(request):
    today = get_custom_today()
    member = request.user.member
    basic_info, created = BasicInformation.objects.get_or_create(member=member)
    service_info, created = ServiceInformation.objects.get_or_create(member=member)
    special_quality_info = SpecialQualityInformation.objects.filter(member=member)
    families = FamilyInformation.objects.filter(member=member)
    educations = EducationInformation.objects.filter(member=member)
    rd = relativedelta(today, member.created_at.date())
    doe = f"{rd.years} years, {rd.months} months, {rd.days} days"
    if member.picture:
        picture=member.picture.url
    else:
        picture=None
    leave_types = [key for key, label in MainLeave.CHOICE_LIST]
    allLeave = Leave.objects.filter(member=member,leave_type__name__in=leave_types).order_by('-created_at', '-id')
    # Group by created_at date (ignoring time)
    grouped_history = []
    for key, group in groupby(allLeave, key=lambda x: x.start_date):
        group_list = list(group)
        grouped_history.append(group_list[0])  # Take the first object from each group
        #pagination for leaveHistory
    paginator = Paginator(grouped_history, 50)
    page_number = request.GET.get('page')
    grouped_history = paginator.get_page(page_number)
        
    #movement order history
    movement_orders = MovementOrder.objects.filter(member=member).order_by('-created_at', '-id')
    # pagination for movement orders
    paginator = Paginator(movement_orders, 50)  # 50 records per page
    page_number = request.GET.get('page')
    movement_orders = paginator.get_page(page_number)
    
    #punishment history
    punishments = Punishment.objects.filter(member=member).order_by('-created_at', '-id')
    # pagination for punishment
    paginator = Paginator(punishments, 50)  # 50 records per page
    page_number = request.GET.get('page')
    punishments = paginator.get_page(page_number)
    
    #punishment history
    promotions = Promotion.objects.filter(member=member).order_by('-created_at', '-id')
    # pagination for punishment
    paginator = Paginator(promotions, 50)  # 50 records per page
    page_number = request.GET.get('page')
    promotions = paginator.get_page(page_number)
    context = {
        "member":member,
        "doe":doe,
        "picture":picture,
        "leaves":grouped_history,
        "movement_orders":movement_orders,
        "punishments":punishments,
        "promotions":promotions,
        "basic_info":basic_info,
        "service_info":service_info,
        'special_quality_info':special_quality_info,
        "families":families,
        "educations":educations
    }
    return render(request,"member/member_profile.html",context)




def editMemberBasicMember(request,id):
    member = Member.objects.get(id=id)
    blood_groups = [(key,value) for key, value in BasicInformation.BLOOD_LIST]
    marital_statuses = [(key,value) for key, value in BasicInformation.MARITAL_STATUS_LIST]
    genders = [(key,value) for key, value in BasicInformation.GENDER_LIST]
    districts = District.objects.all()
    basic_info, created = BasicInformation.objects.get_or_create(member=member)
    if request.method == 'POST':
        blood = request.POST.get('blood')
        email = request.POST.get('email')
        nid = request.POST.get('nid')
        birth = request.POST.get('birth')
        passport = request.POST.get('passport')
        bank = request.POST.get('bank')
        religion = request.POST.get('religion')
        height = request.POST.get('height')
        district_id = request.POST.get('district')
        upazila_id = request.POST.get('upazila')
        date_of_birth = request.POST.get('date_of_birth')
        gender = request.POST.get('gender')
        marital_status = request.POST.get('marital_status')
        em_name = request.POST.get('em_name')
        em_mobile_no = request.POST.get('em_mobile_no')
        mobile_no = request.POST.get('mobile_no')
        picture = request.FILES.get('picture')
        # Check if all fields are provided
        if not all([mobile_no]):
            messages.error(request, "Mobile No fields are required")
        try:
            if district_id:
                district = District.objects.get(id=district_id)
                basic_info.district = district
            if upazila_id:
                upazila = Upazila.objects.get(id=upazila_id)
                basic_info.upazila = upazila
            basic_info.blood = blood
            basic_info.email = email
            basic_info.nid = nid
            basic_info.birth = birth
            basic_info.passport = passport
            basic_info.bank = bank
            basic_info.religion = religion
            basic_info.height = height
            if date_of_birth:
                basic_info.date_of_birth = date_of_birth
            else:
                basic_info.date_of_birth = None
            basic_info.date_of_birth = date_of_birth
            basic_info.gender = gender
            basic_info.marital_status = marital_status
            basic_info.em_name = em_name
            basic_info.em_mobile_no = em_mobile_no
            member.mobile_no = mobile_no
            if picture:
                member.picture = picture
            basic_info.save()
            member.save() 
            messages.success(request, "Basic Information Updated Successfully")
        except Exception as e:
            messages.error(request, "An error occurred while updating basic information")
            print("error",e)
        return redirect('memberProfile')
    context = {
        "member":member,
        "blood_groups":blood_groups,
        "marital_statuses":marital_statuses,
        "genders":genders,
        "districts":districts,
        "basic_info":basic_info
    }
    return render(request,'member/edit_basic.html',context)

def editMemberServiceMember(request,id):
    member = Member.objects.get(id=id)
    med_cats = ServiceInformation.MED_CAT_LIST
    un_msns = ServiceInformation.UN_MSN_LIST
    trades = Trade.objects.all()
    cores = Core.objects.all()
    service, created = ServiceInformation.objects.get_or_create(member=member)
    if request.method == 'POST':
        med_cat = request.POST.get('med_cat')
        un_msn = request.POST.get('un_msn')
        trade_id = request.POST.get('trade')
        core_id = request.POST.get('core')
        retirement = request.POST.get('retirement')
        try:
            if trade_id:
                trade = Trade.objects.get(id=trade_id)
                service.trade = trade
            if core_id:
                core = Core.objects.get(id=core_id)
                service.core = core
            service.med_cat = med_cat
            service.un_msn = un_msn
            if retirement:
                service.retirement = retirement
            else:
                service.retirement = None
            service.save()
            messages.success(request, "Service Information Updated Successfully")
        except Exception as e:
            messages.error(request, "An error occurred while updating Service information")
            print("error",e)
        return redirect('memberProfile')
    context = {
        "member":member,
        "med_cats":med_cats,
        "un_msns":un_msns,
        "trades":trades,
        "cores":cores,
        "service":service
    }
    return render(request,'member/edit_service.html',context)

def addSpecialQualityInfoMember(request,id):
    member = Member.objects.get(id=id)
    special_quality_info = SpecialQualityInformation.objects.filter(member=member)
    special_qualities = SpecialQuality.objects.all()
    if request.method == 'POST':
        special_quality_id = request.POST.get('special_quality')
        description = request.POST.get('description')
        # Check if all fields are provided
        if not all([special_quality_id]):
            messages.error(request, "FIll Name fields")
        try:
            special_quality = SpecialQuality.objects.get(id=special_quality_id)
            SpecialQualityInformation.objects.create(member=member,special_quality=special_quality,description=description)
            messages.success(request, "SpecialQuality Information Added Successfully")
        except Exception as e:
            messages.error(request, "An error occurred while adding family information")
        return redirect('addSpecialQualityInfoMember',id=id)
    context = {
        "member":member,
        "special_quality_info":special_quality_info,
        "special_qualities":special_qualities
    }
    return render(request,'member/add_special_quality_info.html',context)

def deleteSpecialQualityInfoMember(request,id):
    special_quality_info = SpecialQualityInformation.objects.get(id=id)
    special_quality_info.delete()
    messages.success(request, "Special Quality Information Deleted Successfully")
    return redirect('addSpecialQualityInfoMember',id=special_quality_info.member.id)

def addFamilyMember(request,id):
    member = Member.objects.get(id=id)
    relations = [(key,value) for key, value in FamilyInformation.REL_LIST] 
    genders = [(key,value) for key, value in FamilyInformation.GENDER_LIST]
    families = FamilyInformation.objects.filter(member=member)
    if request.method == 'POST':
        relationship = request.POST.get('relationship')
        name = request.POST.get('name')
        nid = request.POST.get('nid')
        date_of_birth = request.POST.get('date_of_birth')
        gender = request.POST.get('gender')
        mobile_no = request.POST.get('mobile_no')
        picture = request.FILES.get('picture')
        # Check if all fields are provided
        if not all([name,relationship,gender]):
            messages.error(request, "FIll all fields")
        if not picture:
            picture = None
        try:
            FamilyInformation.objects.create(member=member,relationship=relationship,name=name,nid=nid,date_of_birth=date_of_birth,gender=gender,mobile_no=mobile_no,picture=picture)
            messages.success(request, "Family Information Added Successfully")
        except Exception as e:
            messages.error(request, "An error occurred while adding family information")
        return redirect('addFamilyMember',id=id)
    context = {
        "member":member,
        "relations":relations,
        "genders":genders,
        "families":families
    }
    return render(request,'member/add_family.html',context)
    
def deleteFamilyMember(request,id):
    family = FamilyInformation.objects.get(id=id)
    family.delete()
    messages.success(request, "Family Information Deleted Successfully")
    return redirect('addFamilyMember',id=family.member.id)


def addEducationMember(request,id):
    member = Member.objects.get(id=id)
    educations = EducationInformation.objects.filter(member=member)
    if request.method == 'POST':
        name = request.POST.get('name')
        institution = request.POST.get('institution')
        board = request.POST.get('board')
        roll = request.POST.get('roll')
        reg = request.POST.get('reg')
        year = request.POST.get('year')
        gpa = request.POST.get('gpa')
        # Check if all fields are provided
        if not all([name]):
            messages.error(request, "FIll Name fields")
        try:
            EducationInformation.objects.create(member=member,board=board,name=name,roll=roll,reg=reg,year=year,gpa=gpa,institution=institution)
            messages.success(request, "Education Information Added Successfully")
        except Exception as e:
            messages.error(request, "An error occurred while adding family information")
        return redirect('addEducationMember',id=id)
    context = {
        "member":member,
        "educations":educations
    }
    return render(request,'member/add_education.html',context)
    
def deleteEducationMember(request,id):
    education = EducationInformation.objects.get(id=id)
    education.delete()
    messages.success(request, "Family Information Deleted Successfully")
    return redirect('addEducationMember',id=education.member.id)


def leave_apply_member(request):
    if request.method == "POST":
        member = request.user.member
        leave_type_id = request.POST.get("leave_type")
        start_date = request.POST.get("start_date")
        end_date = request.POST.get("end_date")
        reason_id = request.POST.get("reason")
        reason_des_id = request.POST.get("reason_des")
        status = request.POST.get("status", "pending")
        
        # Convert the start and end date strings into datetime objects
        start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
        end_date_obj = datetime.strptime(end_date, "%Y-%m-%d")

        # Calculate the number of days (including the start date)
        days = (end_date_obj - start_date_obj).days + 1

        leave_type = get_object_or_404(LeaveType, id=leave_type_id)
        
        #check any leave exists in the date range for the member
        existing_leaves = Leave.objects.filter(
            member=member,
            date__range=(start_date_obj, end_date_obj)
        )
        if existing_leaves.exists():
            messages.error(request, "Leave already exists for the member in the date range")
            return redirect('leave_apply_member')
        reason = LeaveReason.objects.get(id=reason_id) if reason_id else None
        reason_des = LeaveReasonDes.objects.get(id=reason_des_id) if reason_des_id else None
        ApplyLeave.objects.create(
            member=member,
            leave_type=leave_type,
            start_date=start_date,
            end_date=end_date,
            reason=reason,
            reason_des=reason_des,
            days=days,
            status=status,
            apply_by=member.army_no
        )

        messages.success(request, "Leave application submitted successfully!")
        return redirect("leave_apply_member")
    #pagination for leaveHistory
    leaveHistory = ApplyLeave.objects.filter(member=request.user.member).order_by('-id')
    paginator = Paginator(leaveHistory, 30)
    page_number = request.GET.get('page')
    leaveHistory = paginator.get_page(page_number)
    leave_types = [key for key, label in ApplyLeave.CHOICE_LIST]
    leave_types = LeaveType.objects.filter(name__in=leave_types)
    reasons = LeaveReason.objects.all()
    context = {
        'leaveTypes':leave_types,
        'leaveHistory':leaveHistory,
        'reasons':reasons
    }
    
    return render(request,"member/leave.html",context)


