from django.contrib import messages
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone
from django.views.generic import CreateView, DetailView, ListView, UpdateView, View

from apps.core.permissions.mixins import RimsAccessMixin
from apps.core.permissions.roles import UserRole
from apps.rims.hr.forms import (
    BackToOfficeForm,
    DepartmentForm,
    LeaveRequestForm,
    LeaveReviewForm,
    StaffProfileForm,
    TravelReportForm,
    TravelRequestForm,
)
from apps.rims.hr.models import (
    BackToOfficeReport,
    Department,
    LeaveRequest,
    StaffProfile,
    TravelReport,
    TravelRequest,
)


class HRAdminMixin(RimsAccessMixin):
    allowed_roles = (
        UserRole.ADMIN,
        UserRole.GRANTS_MANAGER,
        UserRole.PROGRAMME_OFFICER,
        UserRole.HUMAN_RESOURCE,
    )


class HRStaffMixin(RimsAccessMixin):
    """Any authenticated staff member — they see their own records."""
    allowed_roles = tuple(r.value for r in UserRole)


# --- Staff Bio-database ---

class StaffListView(HRAdminMixin, ListView):
    model = StaffProfile
    template_name = "hr/staff_list.html"
    context_object_name = "staff_profiles"
    paginate_by = 20

    def get_queryset(self):
        qs = StaffProfile.objects.select_related("user", "department", "supervisor")
        q = (self.request.GET.get("q") or "").strip()
        if q:
            qs = qs.filter(
                Q(user__first_name__icontains=q)
                | Q(user__last_name__icontains=q)
                | Q(user__email__icontains=q)
                | Q(job_title__icontains=q)
                | Q(employee_id__icontains=q)
            )
        dept = self.request.GET.get("department")
        if dept:
            qs = qs.filter(department_id=dept)
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["departments"] = Department.objects.all()
        return ctx

    def get_template_names(self):
        if getattr(self.request, "htmx", False):
            return ["hr/partials/staff_list_results.html"]
        return super().get_template_names()


class StaffDetailView(HRAdminMixin, DetailView):
    model = StaffProfile
    template_name = "hr/staff_detail.html"
    context_object_name = "profile"

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["leave_requests"] = self.object.leave_requests.select_related("leave_type").order_by("-created_at")[:10]
        ctx["travel_requests"] = self.object.travel_requests.order_by("-created_at")[:10]
        return ctx


class StaffCreateView(HRAdminMixin, CreateView):
    model = StaffProfile
    form_class = StaffProfileForm
    template_name = "hr/staff_form.html"

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:staff_detail", kwargs={"pk": self.object.pk})


class StaffUpdateView(HRAdminMixin, UpdateView):
    model = StaffProfile
    form_class = StaffProfileForm
    template_name = "hr/staff_edit.html"

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:staff_detail", kwargs={"pk": self.object.pk})


# --- Departments ---

class DepartmentListView(HRAdminMixin, ListView):
    model = Department
    template_name = "hr/department_list.html"
    context_object_name = "departments"

    def get_queryset(self):
        return Department.objects.select_related("head").annotate_staff_count()  # type: ignore[attr-defined]

    def get_queryset(self):
        from django.db.models import Count
        return Department.objects.select_related("head").annotate(staff_count=Count("staff"))


class DepartmentCreateView(HRAdminMixin, CreateView):
    model = Department
    form_class = DepartmentForm
    template_name = "hr/department_form.html"

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:department_list")


class DepartmentUpdateView(HRAdminMixin, UpdateView):
    model = Department
    form_class = DepartmentForm
    template_name = "hr/department_edit.html"

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:department_list")


# --- Leave ---

class LeaveRequestListView(HRAdminMixin, ListView):
    model = LeaveRequest
    template_name = "hr/leave_list.html"
    context_object_name = "leave_requests"
    paginate_by = 20

    def get_queryset(self):
        qs = LeaveRequest.objects.select_related("staff__user", "leave_type", "reviewed_by")
        status = self.request.GET.get("status")
        if status:
            qs = qs.filter(status=status)
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["status_choices"] = LeaveRequest.Status.choices
        return ctx

    def get_template_names(self):
        if getattr(self.request, "htmx", False):
            return ["hr/partials/leave_list_results.html"]
        return super().get_template_names()


class MyLeaveListView(HRStaffMixin, ListView):
    model = LeaveRequest
    template_name = "hr/my_leave_list.html"
    context_object_name = "leave_requests"
    paginate_by = 20

    def get_queryset(self):
        try:
            profile = self.request.user.staff_profile
        except StaffProfile.DoesNotExist:
            return LeaveRequest.objects.none()
        return LeaveRequest.objects.filter(staff=profile).select_related("leave_type")


class LeaveRequestCreateView(HRStaffMixin, CreateView):
    model = LeaveRequest
    form_class = LeaveRequestForm
    template_name = "hr/leave_form.html"

    def form_valid(self, form):
        try:
            form.instance.staff = self.request.user.staff_profile
        except StaffProfile.DoesNotExist:
            messages.error(self.request, "You do not have a staff profile. Contact HR.")
            return self.form_invalid(form)
        messages.success(self.request, "Leave request submitted.")
        return super().form_valid(form)

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:my_leave_list")


class LeaveReviewView(HRAdminMixin, UpdateView):
    model = LeaveRequest
    form_class = LeaveReviewForm
    template_name = "hr/leave_review.html"

    def form_valid(self, form):
        form.instance.reviewed_by = self.request.user
        form.instance.reviewed_at = timezone.now()
        messages.success(self.request, f"Leave request {form.instance.get_status_display().lower()}.")
        return super().form_valid(form)

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:leave_list")


class BackToOfficeCreateView(HRStaffMixin, CreateView):
    model = BackToOfficeReport
    form_class = BackToOfficeForm
    template_name = "hr/bto_form.html"

    def form_valid(self, form):
        try:
            form.instance.staff = self.request.user.staff_profile
        except StaffProfile.DoesNotExist:
            messages.error(self.request, "You do not have a staff profile. Contact HR.")
            return self.form_invalid(form)
        leave_pk = self.request.GET.get("leave")
        if leave_pk:
            form.instance.leave_request_id = leave_pk
        messages.success(self.request, "Back-to-office report submitted.")
        return super().form_valid(form)

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:my_leave_list")


class BackToOfficeListView(HRAdminMixin, ListView):
    model = BackToOfficeReport
    template_name = "hr/bto_list.html"
    context_object_name = "reports"
    paginate_by = 20

    def get_queryset(self):
        return BackToOfficeReport.objects.select_related("staff__user", "leave_request__leave_type")


# --- Travel ---

class TravelRequestListView(HRAdminMixin, ListView):
    model = TravelRequest
    template_name = "hr/travel_list.html"
    context_object_name = "travel_requests"
    paginate_by = 20

    def get_queryset(self):
        qs = TravelRequest.objects.select_related("staff__user", "approved_by")
        status = self.request.GET.get("status")
        if status:
            qs = qs.filter(status=status)
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["status_choices"] = TravelRequest.Status.choices
        return ctx

    def get_template_names(self):
        if getattr(self.request, "htmx", False):
            return ["hr/partials/travel_list_results.html"]
        return super().get_template_names()


class MyTravelListView(HRStaffMixin, ListView):
    model = TravelRequest
    template_name = "hr/my_travel_list.html"
    context_object_name = "travel_requests"
    paginate_by = 20

    def get_queryset(self):
        try:
            profile = self.request.user.staff_profile
        except StaffProfile.DoesNotExist:
            return TravelRequest.objects.none()
        return TravelRequest.objects.filter(staff=profile)


class TravelRequestCreateView(HRStaffMixin, CreateView):
    model = TravelRequest
    form_class = TravelRequestForm
    template_name = "hr/travel_form.html"

    def form_valid(self, form):
        try:
            form.instance.staff = self.request.user.staff_profile
        except StaffProfile.DoesNotExist:
            messages.error(self.request, "You do not have a staff profile. Contact HR.")
            return self.form_invalid(form)
        messages.success(self.request, "Travel request submitted for approval.")
        return super().form_valid(form)

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:my_travel_list")


class TravelApproveView(HRAdminMixin, View):
    def post(self, request, pk):
        tr = get_object_or_404(TravelRequest, pk=pk)
        action = request.POST.get("action")
        if action == "approve":
            tr.status = TravelRequest.Status.APPROVED
            tr.approved_by = request.user
            tr.approved_at = timezone.now()
            tr.save(update_fields=["status", "approved_by", "approved_at"])
            messages.success(request, "Travel request approved.")
        elif action == "reject":
            tr.status = TravelRequest.Status.REJECTED
            tr.save(update_fields=["status"])
            messages.warning(request, "Travel request rejected.")
        from django.urls import reverse
        return redirect(reverse("rims_hr:travel_list"))


class TravelReportCreateView(HRStaffMixin, CreateView):
    model = TravelReport
    form_class = TravelReportForm
    template_name = "hr/travel_report_form.html"

    def dispatch(self, request, *args, **kwargs):
        self.travel_request = get_object_or_404(TravelRequest, pk=kwargs["travel_pk"])
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        form.instance.travel_request = self.travel_request
        self.travel_request.status = TravelRequest.Status.COMPLETED
        self.travel_request.save(update_fields=["status"])
        messages.success(self.request, "Travel report submitted.")
        return super().form_valid(form)

    def get_success_url(self):
        from django.urls import reverse
        return reverse("rims_hr:my_travel_list")
