import json
import io
import zipfile
from django.forms import HiddenInput
from django.core.paginator import Paginator
from django.utils.translation import gettext as _
from django.contrib.auth import get_user_model, authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.mixins import LoginRequiredMixin
from .decorators import (
    agency_user_required,
    candidate_user_required,
    staff_user_required,
    staff_or_agency_required,
    staff_or_candidate_required,
    AgencyRequiredMixin,
    CandidateRequiredMixin,
    StaffRequiredMixin,
    StaffOrAgencyRequiredMixin,
    StaffOrCandidateRequiredMixin,
)
from .forms import (
    StaffUserCreationForm,
    ToggleAccountForm,
    JobPostingStatusForm,
    LinkedPostContentForm,
    CandidateEmailForm,
    InterviewForm,
    ProfileImageUploadForm,
    ParticipantsSelectForm,
    ApplicationForm,
    PasswordResetForm,
    StaffAssignmentForm,
)
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse, JsonResponse
from datetime import datetime, time, timedelta
from django.views import View
from django.urls import reverse
from django.conf import settings
from django.utils import timezone
from django.db.models import FloatField, CharField, DurationField
from django.db.models import (
    F,
    IntegerField,
    Count,
    Avg,
    Sum,
    Q,
    ExpressionWrapper,
    fields,
    Value
)
from django.db.models.functions import Coalesce, Cast, Replace, NullIf
from django.db.models.functions import Cast, Coalesce, TruncDate
from django.db.models.fields.json import KeyTextTransform
from django.db.models.expressions import ExpressionWrapper
from django.urls import reverse_lazy
from django.db.models import Count, Avg, F, Q
from .forms import (
    ZoomMeetingForm,
    CandidateExamDateForm,
    JobPostingForm,
    JobPostingImageForm,
    InterviewNoteForm,
    InterviewScheduleForm,
    FormTemplateForm,
    SourceForm,
    HiringAgencyForm,
    AgencyJobAssignmentForm,
    AgencyAccessLinkForm,
    AgencyApplicationSubmissionForm,
    AgencyLoginForm,
    PortalLoginForm,
    MessageForm,
    PersonForm,
    OnsiteLocationForm,
    OnsiteReshuduleForm,
    OnsiteScheduleForm,
    InterviewEmailForm
)
from easyaudit.models import CRUDEvent, LoginEvent, RequestEvent
from rest_framework import viewsets
from django.contrib import messages
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .linkedin_service import LinkedInService
from .serializers import JobPostingSerializer, ApplicationSerializer
from django.shortcuts import get_object_or_404, render, redirect
from django.views.generic import (
    CreateView,
    UpdateView,
    DetailView,
    ListView,
    DeleteView,
)
from .utils import (
    create_zoom_meeting,
    delete_zoom_meeting,
    get_candidates_from_request,
    update_meeting,
    update_zoom_meeting,
    get_zoom_meeting_details,
    schedule_interviews,
    get_available_time_slots,
)
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_POST
from .models import (
    FormTemplate,
    FormStage,
    FormField,
    FieldResponse,
    FormSubmission,
    InterviewSchedule,
    BreakTime,
    ZoomMeetingDetails,
    Application,
    Person,
    JobPosting,
    ScheduledInterview,
    JobPostingImage,

    HiringAgency,
    AgencyJobAssignment,
    AgencyAccessLink,
    Notification,
    Source,
    Message,
    Document,
    OnsiteLocationDetails,
    InterviewLocation,
    InterviewNote
)


import logging
from datastar_py.django import (
    DatastarResponse,
    ServerSentEventGenerator as SSE,
    read_signals,
)
from django.db import transaction
from django_q.tasks import async_task
from django.db.models import Prefetch
from django.db.models import Q, Count, Avg
from django.db.models import FloatField
from django.urls import reverse_lazy

logger = logging.getLogger(__name__)

User = get_user_model()


class PersonListView(StaffRequiredMixin, ListView):
    model = Person
    template_name = "people/person_list.html"
    context_object_name = "people_list"
    def get_queryset(self):
        queryset=super().get_queryset()
        gender=self.request.GET.get('gender')
        if gender:
            queryset=queryset.filter(gender=gender)
        
        nationality=self.request.GET.get('nationality')
        if nationality:
            queryset=queryset.filter(nationality=nationality)
        
        return queryset
    def get_context_data(self, **kwargs):
        context=super().get_context_data(**kwargs)
        # We query the base model to ensure we list ALL options, not just those currently displayed.
        nationalities = self.model.objects.values_list('nationality', flat=True).filter(
            nationality__isnull=False
        ).distinct().order_by('nationality')
        
        nationality=self.request.GET.get('nationality')
        context['nationality']=nationality
        context['nationalities']=nationalities
        return context



class PersonCreateView(CreateView):
    model = Person
    template_name = "people/create_person.html"
    form_class = PersonForm
    success_url = reverse_lazy("person_list")
    print("from agency")
    def form_valid(self, form):
        if "HX-Request" in self.request.headers:
            instance = form.save()
            view = self.request.POST.get("view")
            if view == "portal":
                slug = self.request.POST.get("agency")
                if slug:
                    agency = HiringAgency.objects.get(slug=slug)
                    print(agency)
                    instance.agency = agency
                    instance.save()
                return redirect("agency_portal_persons_list")
            if view == "job":
                return redirect("candidate_create")
        return super().form_valid(form)



class PersonDetailView(DetailView):
    model = Person
    template_name = "people/person_detail.html"
    context_object_name = "person"


class PersonUpdateView(StaffRequiredMixin, UpdateView):
    model = Person
    template_name = "people/update_person.html"
    form_class = PersonForm
    success_url = reverse_lazy("person_list")


class PersonDeleteView(StaffRequiredMixin, DeleteView):
    model = Person
    template_name = "people/delete_person.html"
    success_url = reverse_lazy("person_list")


class JobPostingViewSet(viewsets.ModelViewSet):
    queryset = JobPosting.objects.all()
    serializer_class = JobPostingSerializer


class CandidateViewSet(viewsets.ModelViewSet):
    queryset = Application.objects.all()
    serializer_class = ApplicationSerializer


class ZoomMeetingCreateView(StaffRequiredMixin, CreateView):
    model = ZoomMeetingDetails
    template_name = "meetings/create_meeting.html"
    form_class = ZoomMeetingForm
    success_url = "/"

    def form_valid(self, form):
        instance = form.save(commit=False)
        try:
            topic = instance.topic
            if instance.start_time < timezone.now():
                messages.error(self.request, "Start time must be in the future.")
                return redirect(
                    reverse("create_meeting", kwargs={"slug": instance.slug})
                )
            start_time = instance.start_time
            duration = instance.duration

            result = create_zoom_meeting(topic, start_time, duration)
            if result["status"] == "success":
                instance.meeting_id = result["meeting_details"]["meeting_id"]
                instance.join_url = result["meeting_details"]["join_url"]
                instance.host_email = result["meeting_details"]["host_email"]
                instance.password = result["meeting_details"]["password"]
                instance.status = result["zoom_gateway_response"]["status"]
                instance.zoom_gateway_response = result["zoom_gateway_response"]
                instance.save()
                messages.success(self.request, result["message"])

                return redirect(reverse("list_meetings"))
            else:
                messages.error(self.request, result["message"])
                return redirect(
                    reverse("create_meeting", kwargs={"slug": instance.slug})
                )
        except Exception as e:
            messages.error(self.request, f"Error creating meeting: {e}")
            return redirect(reverse("create_meeting", kwargs={"slug": instance.slug}))



class ZoomMeetingDetailsView(StaffRequiredMixin, DetailView):
    model = ZoomMeetingDetails
    template_name = "meetings/meeting_details.html"
    context_object_name = "meeting"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        meeting = self.object
        try:
            interview = meeting.interview
        except Exception as e:
            print(e)
        candidate = interview.candidate
        job = meeting.get_job

        # Assuming interview.participants and interview.system_users hold the people:
        participants = list(interview.participants.all()) + list(
            interview.system_users.all()
        )
        external_participants = list(interview.participants.all())
        system_participants = list(interview.system_users.all())
        total_participants = len(participants)
        form = InterviewParticpantsForm(instance=interview)
        context["form"] = form
        context["email_form"] = InterviewEmailForm(
            candidate=candidate,
            external_participants=external_participants,
            system_participants=system_participants,
            meeting=meeting,
            job=job,
        )
        context["total_participants"] = total_participants
        return context


class ZoomMeetingUpdateView(StaffRequiredMixin, UpdateView):
    model = ZoomMeetingDetails
    form_class = ZoomMeetingForm
    context_object_name = "meeting"
    template_name = "meetings/update_meeting.html"
    success_url = "/"

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        # Ensure the form is initialized with the instance's current values
        if self.object:
            kwargs['initial'] = getattr(kwargs, 'initial', {})
            initial_start_time = ""
            if self.object.start_time:
                try:
                    initial_start_time = self.object.start_time.strftime('%m-%d-%Y,T%H:%M')
                except AttributeError:
                    print(f"Warning: start_time {self.object.start_time} is not a datetime object.")
                    initial_start_time = ""
            kwargs['initial']['start_time'] = initial_start_time
        return kwargs

    def form_valid(self, form):
        instance = form.save(commit=False)
        updated_data = {
            "topic": instance.topic,
            "start_time": instance.start_time.isoformat() + "Z",
            "duration": instance.duration,
        }
        if instance.start_time < timezone.now():
            messages.error(self.request, "Start time must be in the future.")
            return redirect(reverse("meeting_details", kwargs={"slug": instance.slug}))

        result = update_meeting(instance, updated_data)

        if result["status"] == "success":
            messages.success(self.request, result["message"])
        else:
            messages.error(self.request, result["message"])
        return redirect(reverse("meeting_details", kwargs={"slug": instance.slug}))


def ZoomMeetingDeleteView(request, slug):
    meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
    if "HX-Request" in request.headers:
        return render(
            request,
            "meetings/delete_meeting_form.html",
            {
                "meeting": meeting,
                "delete_url": reverse("delete_meeting", kwargs={"slug": meeting.slug}),
            },
        )
    if request.method == "POST":
        try:
            result = delete_zoom_meeting(meeting.meeting_id)
            if (
                result["status"] == "success"
                or "Meeting does not exist" in result["details"]["message"]
            ):
                meeting.delete()
                messages.success(request, "Meeting deleted successfully.")
            else:
                messages.error(
                    request, f"{result['message']} , {result['details']['message']}"
                )
            return redirect(reverse("list_meetings"))
        except Exception as e:
            messages.error(request, str(e))
            return redirect(reverse("list_meetings"))

# Job Posting
# def job_list(request):
#     """Display the list of job postings order by creation date descending"""
#     jobs=JobPosting.objects.all().order_by('-created_at')

#     # Filter by status if provided
#     print(f"the request is: {request} ")
#     status=request.GET.get('status')
#     print(f"DEBUG: Status filter received: {status}")
#     if status:
#         jobs=jobs.filter(status=status)

#     #pagination
#     paginator=Paginator(jobs,10) # Show 10 jobs per page
#     page_number=request.GET.get('page')
#     page_obj=paginator.get_page(page_number)
#     return render(request, 'jobs/job_list.html', {
#         'page_obj': page_obj,
#         'status_filter': status
#     })


@login_required
@staff_user_required
def create_job(request):
    """Create a new job posting"""

    if request.method == "POST":
        form = JobPostingForm(request.POST)
        # to check user is authenticated or not
        if form.is_valid():
            try:
                job = form.save(commit=False)
                job.save()
                job_apply_url_relative = reverse(
                    "application_detail", kwargs={"slug": job.slug}
                )
                job_apply_url_absolute = request.build_absolute_uri(
                    job_apply_url_relative
                )
                job.application_url = job_apply_url_absolute
                # FormTemplate.objects.create(job=job, is_active=False, name=job.title,created_by=request.user)
                job.save()
                messages.success(request, f'Job "{job.title}" created successfully!')
                return redirect("job_list")
            except Exception as e:
                logger.error(f"Error creating job: {e}")
                messages.error(request, f"Error creating job: {e}")
        else:
            messages.error(request, f"Please correct the errors below.{form.errors}")
    else:
        form = JobPostingForm()
    return render(request, "jobs/create_job.html", {"form": form})


@login_required
@staff_user_required
def edit_job(request, slug):
    """Edit an existing job posting"""
    job = get_object_or_404(JobPosting, slug=slug)
    if request.method == "POST":
        form = JobPostingForm(request.POST, instance=job)
        if form.is_valid():
            try:
                form.save()
                messages.success(request, f'Job "{job.title}" updated successfully!')
                return redirect("job_list")
            except Exception as e:
                logger.error(f"Error updating job: {e}")
                messages.error(request, f"Error updating job: {e}")
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        job = get_object_or_404(JobPosting, slug=slug)
        form = JobPostingForm(instance=job)
    return render(request, "jobs/edit_job.html", {"form": form, "job": job})


SCORE_PATH = "ai_analysis_data__analysis_data__match_score"
HIGH_POTENTIAL_THRESHOLD = 75
from django.contrib.sites.shortcuts import get_current_site


@staff_user_required
def job_detail(request, slug):
    """View details of a specific job"""
    job = get_object_or_404(JobPosting, slug=slug)
    # Get all applications for this job, ordered by most recent
    applicants = job.applications.all().order_by("-created_at")

    # Count applications by stage for summary statistics
    total_applicant = applicants.count()

    applied_count = applicants.filter(stage="Applied").count()

    exam_count = applicants.filter(stage="Exam").count()

    interview_count = applicants.filter(stage="Interview").count()

    offer_count = applicants.filter(stage="Offer").count()

    status_form = JobPostingStatusForm(instance=job)
    linkedin_content_form = LinkedPostContentForm(instance=job)
    try:
        # If the related object exists, use its instance data
        image_upload_form = JobPostingImageForm(instance=job.post_images)
    except Exception as e:
        # If the related object does NOT exist, create a blank form
        image_upload_form = JobPostingImageForm()

    # 2. Check for POST request (Status Update Submission)
    if request.method == "POST":
        status_form = JobPostingStatusForm(request.POST, instance=job)

        if status_form.is_valid():
            job_status = status_form.cleaned_data["status"]
            form_template = job.form_template
            if job_status == "ACTIVE":
                form_template.is_active = True
                form_template.save(update_fields=["is_active"])
            else:
                form_template.is_active = False
                form_template.save(update_fields=["is_active"])

            status_form.save()

            # Add a success message
            messages.success(
                request,
                f"Status for '{job.title}' updated to '{job.get_status_display()}' successfully!",
            )

            return redirect("job_detail", slug=slug)
        else:
            messages.error(request, "Failed to update status due to validation errors.")

    # --- 2. Quality Metrics (JSON Aggregation) ---



    candidates_with_score = applicants.filter(is_resume_parsed=True).annotate(
        annotated_match_score=Coalesce(Cast(SCORE_PATH, output_field=IntegerField()), 0)
    )

    total_candidates = applicants.count()
    avg_match_score_result = candidates_with_score.aggregate(
        avg_score=Avg("annotated_match_score")
    )["avg_score"]
    avg_match_score = round(avg_match_score_result or 0, 1)
    high_potential_count = candidates_with_score.filter(
        annotated_match_score__gte=HIGH_POTENTIAL_THRESHOLD
    ).count()
    high_potential_ratio = (
        round((high_potential_count / total_candidates) * 100, 1)
        if total_candidates > 0
        else 0
    )

    # --- 3. Time Metrics (Duration Aggregation) ---

    # Metric: Average Time from Applied to Interview (T2I)
    t2i_candidates = applicants.filter(interview_date__isnull=False).annotate(
        time_to_interview=ExpressionWrapper(
            F("interview_date") - F("created_at"), output_field=DurationField()
        )
    )
    avg_t2i_duration = t2i_candidates.aggregate(avg_t2i=Avg("time_to_interview"))[
        "avg_t2i"
    ]

    # Convert timedelta to days
    avg_t2i_days = (
        round(avg_t2i_duration.total_seconds() / (60 * 60 * 24), 1)
        if avg_t2i_duration
        else 0
    )

    # Metric: Average Time in Exam Stage
    t_in_exam_candidates = applicants.filter(
        exam_date__isnull=False, interview_date__isnull=False
    ).annotate(
        time_in_exam=ExpressionWrapper(
            F("interview_date") - F("exam_date"), output_field=DurationField()
        )
    )
    avg_t_in_exam_duration = t_in_exam_candidates.aggregate(
        avg_t_in_exam=Avg("time_in_exam")
    )["avg_t_in_exam"]

    # Convert timedelta to days
    avg_t_in_exam_days = (
        round(avg_t_in_exam_duration.total_seconds() / (60 * 60 * 24), 1)
        if avg_t_in_exam_duration
        else 0
    )

    category_data = (
        applicants.filter(ai_analysis_data__analysis_data__category__isnull=False)
        .values("ai_analysis_data__analysis_data__category")
        .annotate(
            candidate_count=Count("id"),
            category=Cast(
                "ai_analysis_data__analysis_data__category", output_field=CharField()
            ),
        )
        .order_by("ai_analysis_data__analysis_data__category")
    )
    # Prepare data for Chart.js
    print(category_data)
    categories = [item["category"] for item in category_data]
    candidate_counts = [item["candidate_count"] for item in category_data]
    # avg_scores = [round(item['avg_match_score'], 2) if item['avg_match_score'] is not None else 0 for item in category_data]

    context = {
        "job": job,
        "applicants": applicants,
        "total_applicants": total_applicant,  # This was total_candidates in the prompt, using total_applicant for consistency
        "applied_count": applied_count,
        "exam_count": exam_count,
        "interview_count": interview_count,
        "offer_count": offer_count,
        "status_form": status_form,
        "image_upload_form": image_upload_form,
        "categories": categories,
        "candidate_counts": candidate_counts,
        # 'avg_scores': avg_scores,
        # New statistics
        "avg_match_score": avg_match_score,
        "high_potential_count": high_potential_count,
        "high_potential_ratio": high_potential_ratio,
        "avg_t2i_days": avg_t2i_days,
        "avg_t_in_exam_days": avg_t_in_exam_days,
        "linkedin_content_form": linkedin_content_form,
    }
    return render(request, "jobs/job_detail.html", context)


# ALLOWED_EXTENSIONS = (".pdf", ".docx")


# def job_cvs_download(request, slug):
#     job = get_object_or_404(JobPosting, slug=slug)
#     entries = Application.objects.filter(job=job)
    
#     # 2. Create an in-memory byte stream (BytesIO)
#     zip_buffer = io.BytesIO()

#     # 3. Create the ZIP archive
#     with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zf:
#         for entry in entries:
#             # Check if the file field has a file
#             if not entry.resume:
#                 continue

#             # Get the file name and check extension (case-insensitive)
#             file_name = entry.resume.name.split("/")[-1]
#             file_name_lower = file_name.lower()

#             if file_name_lower.endswith(ALLOWED_EXTENSIONS):
#                 try:
#                     # Open the file object (rb is read binary)
#                     file_obj = entry.resume.open("rb")

#                     # *** ROBUST METHOD: Read the content and write it to the ZIP ***
#                     file_content = file_obj.read()

#                     # Write the file content directly to the ZIP archive
#                     zf.writestr(file_name, file_content)

#                     file_obj.close()

#                 except Exception as e:
#                     # Log the error but continue with the rest of the files
#                     print(f"Error processing file {file_name}: {e}")
#                     continue

#     # 4. Prepare the response
#     zip_buffer.seek(0)

#     # 5. Create the HTTP response
#     response = HttpResponse(zip_buffer.read(), content_type="application/zip")

#     # Set the header for the browser to download the file
#     response["Content-Disposition"] = (
#         f'attachment; filename="all_cvs_for_{job.title}.zip"'
#     )

#     return response

def request_cvs_download(request, slug):
    """
    View to initiate the background task.
    """
    job = get_object_or_404(JobPosting, slug=slug)
    job.zip_created = False
    job.save(update_fields=["zip_created"])
    # Use async_task to run the function in the background
    # Pass only simple arguments (like the job ID)
    async_task('recruitment.tasks.generate_and_save_cv_zip', job.id)
    
    # Provide user feedback and redirect
    messages.info(request, "The CV compilation has started in the background. It may take a few moments. Refresh this page to check status.")
    return redirect('job_detail', slug=slug) # Redirect back to the job detail page

def download_ready_cvs(request, slug):
    """
    View to serve the file once it is ready.
    """
    job = get_object_or_404(JobPosting, slug=slug)

    if job.cv_zip_file and job.zip_created:
        # Django FileField handles the HttpResponse and file serving easily
        response = HttpResponse(job.cv_zip_file.read(), content_type="application/zip")
        response["Content-Disposition"] = f'attachment; filename="{job.cv_zip_file.name.split("/")[-1]}"'
        return response
    else:
        # File is not ready or doesn't exist
        messages.warning(request, "The ZIP file is still being generated or an error occurred.")
        return redirect('job_detail', slug=slug)
    
@login_required
@staff_user_required
def job_image_upload(request, slug):
    # only for handling the post request
    job = get_object_or_404(JobPosting, slug=slug)
    try:
        instance = JobPostingImage.objects.get(job=job)
    except JobPostingImage.DoesNotExist:
        # If it doesn't exist, create a new instance placeholder
        instance = None

    if request.method == "POST":
        # Pass the existing instance to the form if it exists
        image_upload_form = JobPostingImageForm(
            request.POST, request.FILES, instance=instance
        )

        if image_upload_form.is_valid():
            # If creating a new one (instance is None), set the job link manually
            if instance is None:
                image_instance = image_upload_form.save(commit=False)
                image_instance.job = job
                image_instance.save()
                messages.success(
                    request, f"Image uploaded successfully for {job.title}."
                )
            else:
                # If updating, the form will update the instance passed to it
                image_upload_form.save()
                messages.success(
                    request, f"Image updated successfully for {job.title}."
                )

        else:
            messages.error(
                request,
                "Image upload failed: Please ensure a valid image file was selected.",
            )
            return redirect("job_detail", slug=job.slug)
    return redirect("job_detail", slug=job.slug)


@login_required
@staff_user_required
def edit_linkedin_post_content(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    linkedin_content_form = LinkedPostContentForm(instance=job)
    if request.method == "POST":
        linkedin_content_form = LinkedPostContentForm(request.POST, instance=job)
        if linkedin_content_form.is_valid():
            linkedin_content_form.save()
            messages.success(request, "Linked post content updated successfully!")
            return redirect("job_detail", job.slug)
        else:
            messages.error(request, "Error update the Linkedin Post content")
            return redirect("job_detail", job.slug)

    else:
        linkedin_content_form = LinkedPostContentForm()
        return redirect("job_detail", job.slug)


JOB_TYPES = [
    ("FULL_TIME", "Full-time"),
    ("PART_TIME", "Part-time"),
    ("CONTRACT", "Contract"),
    ("INTERNSHIP", "Internship"),
    ("FACULTY", "Faculty"),
    ("TEMPORARY", "Temporary"),
]

WORKPLACE_TYPES = [
    ("ON_SITE", "On-site"),
    ("REMOTE", "Remote"),
    ("HYBRID", "Hybrid"),
]


def kaauh_career(request):
    active_jobs = JobPosting.objects.select_related("form_template").filter(
        status="ACTIVE", form_template__is_active=True
    )
    selected_department = request.GET.get("department", "")
    department_type_keys = (
        active_jobs.exclude(department__isnull=True)
        .exclude(department__exact="")
        .values_list("department", flat=True)
        .distinct()
        .order_by("department")
    )

    if selected_department and selected_department in department_type_keys:
        active_jobs = active_jobs.filter(department=selected_department)
    selected_workplace_type = request.GET.get("workplace_type", "")

    selected_job_type = request.GET.get("employment_type", "")

    job_type_keys = active_jobs.order_by("job_type").distinct("job_type").values_list("job_type", flat=True)
    print(job_type_keys)
    workplace_type_keys = active_jobs.order_by("workplace_type").distinct("workplace_type").values_list(
        "workplace_type", flat=True
    ).distinct()
    print(workplace_type_keys)
    if selected_job_type and selected_job_type in job_type_keys:
        active_jobs = active_jobs.filter(job_type=selected_job_type)
    if selected_workplace_type and selected_workplace_type in workplace_type_keys:
        active_jobs = active_jobs.filter(workplace_type=selected_workplace_type)

    JOBS_PER_PAGE = 10
    paginator = Paginator(active_jobs, JOBS_PER_PAGE)
    page_number = request.GET.get("page", 1)

    try:
        page_obj = paginator.get_page(page_number)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    total_open_roles = active_jobs.all().count()

    return render(
        request,
        "applicant/career.html",
        {
            "active_jobs": page_obj.object_list,
            "job_type_keys": job_type_keys,
            "selected_job_type": selected_job_type,
            "workplace_type_keys": workplace_type_keys,
            "selected_workplace_type": selected_workplace_type,
            "selected_department": selected_department,
            "department_type_keys": department_type_keys,
            "total_open_roles": total_open_roles,
            "page_obj": page_obj,
        },
    )


# job detail facing the candidate:
def application_detail(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    return render(request, "applicant/application_detail.html", {"job": job})


@login_required
@staff_user_required
def post_to_linkedin(request, slug):
    """Post a job to LinkedIn"""
    job = get_object_or_404(JobPosting, slug=slug)
    if job.status != "ACTIVE":
        messages.info(request, "Only active jobs can be posted to LinkedIn.")
        return redirect("job_list")

    if request.method == "POST":
        linkedin_access_token = request.session.get("linkedin_access_token")
        # Check if user is authenticated with LinkedIn
        if not "linkedin_access_token":
            messages.error(request, "Please authenticate with LinkedIn first.")
            return redirect("linkedin_login")
        try:
            # Clear previous LinkedIn data for re-posting
            # Prepare the job object for background processing
            job.posted_to_linkedin = False
            job.linkedin_post_id = ""
            job.linkedin_post_url = ""
            job.linkedin_post_status = "QUEUED"
            job.linkedin_posted_at = None
            job.save()

            # ENQUEUE THE TASK
            # Pass the function path, the job slug, and the token as arguments

            async_task(
                "recruitment.tasks.linkedin_post_task", job.slug, linkedin_access_token
            )

            messages.success(
                request,
                _(
                    f"✅ Job posting process for job with JOB ID: {job.internal_job_id} started! Check the job details page in a moment for the final status."
                ),
            )

        except Exception as e:
            logger.error(f"Error enqueuing LinkedIn post: {e}")
            messages.error(
                request, _("Failed to start the job posting process. Please try again.")
            )

    return redirect("job_detail", slug=job.slug)


def linkedin_login(request):
    """Redirect to LinkedIn OAuth"""
    service = LinkedInService()
    auth_url = service.get_auth_url()
    """
    It creates a special URL that:
    Sends the user to LinkedIn to log in
    Asks the user to grant your app permission to post on their behalf
    Tells LinkedIn where to send the user back after they approve (your redirect_uri)
    http://yoursite.com/linkedin/callback/?code=TEMPORARY_CODE_HERE
    """
    return redirect(auth_url)


def linkedin_callback(request):
    """Handle LinkedIn OAuth callback"""
    code = request.GET.get("code")
    if not code:
        messages.error(request, "No authorization code received from LinkedIn.")
        return redirect("job_list")

    try:
        service = LinkedInService()
        # get_access_token(code)->It makes a POST request to LinkedIn's token endpoint with parameters
        access_token = service.get_access_token(code)
        request.session["linkedin_access_token"] = access_token
        request.session["linkedin_authenticated"] = True
        settings.LINKEDIN_IS_CONNECTED = True
        messages.success(request, "Successfully authenticated with LinkedIn!")
    except Exception as e:
        logger.error(f"LinkedIn authentication error: {e}")
        messages.error(request, f"LinkedIn authentication failed: {e}")

    return redirect("job_list")


# applicant views
def applicant_job_detail(request, slug):
    """View job details for applicants"""
    job = get_object_or_404(JobPosting, slug=slug, status="ACTIVE")
    return render(request, "jobs/applicant_job_detail.html", {"job": job})


def application_success(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    return render(request, "jobs/application_success.html", {"job": job})


@ensure_csrf_cookie
@login_required
@staff_user_required
def form_builder(request, template_slug=None):
    """Render the form builder interface"""
    context = {}
    if template_slug:
        template = get_object_or_404(FormTemplate, slug=template_slug)
        context["template"] = template
        context["template_slug"] = template.slug
        context["template_name"] = template.name
    return render(request, "forms/form_builder.html", context)


@csrf_exempt
@require_http_methods(["POST"])
def save_form_template(request):
    """Save a new or existing form template"""
    try:
        data = json.loads(request.body)
        template_name = data.get("name", "Untitled Form")
        stages_data = data.get("stages", [])
        template_slug = data.get("template_slug")

        if template_slug:
            # Update existing template
            template = get_object_or_404(FormTemplate, slug=template_slug)
            template.name = template_name
            template.save()
            # Clear existing stages and fields
            template.stages.all().delete()
        else:
            # Create new template
            template = FormTemplate.objects.create(name=template_name)

        # Create stages and fields
        for stage_order, stage_data in enumerate(stages_data):
            stage = FormStage.objects.create(
                template=template,
                name=stage_data["name"],
                order=stage_order,
                is_predefined=stage_data.get("predefined", False),
            )

            for field_order, field_data in enumerate(stage_data["fields"]):
                options = field_data.get("options", [])
                if not isinstance(options, list):
                    options = []

                file_types = field_data.get("fileTypes", "")
                max_file_size = field_data.get("maxFileSize", 5)

                FormField.objects.create(
                    stage=stage,
                    label=field_data.get("label", ""),
                    field_type=field_data.get("type", "text"),
                    placeholder=field_data.get("placeholder", ""),
                    required=field_data.get("required", False),
                    order=field_order,
                    is_predefined=field_data.get("predefined", False),
                    options=options,
                    file_types=file_types,
                    max_file_size=max_file_size,
                )

        return JsonResponse(
            {
                "success": True,
                "template_slug": template.slug,
                "message": "Form template saved successfully!",
            }
        )
    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)}, status=400)


@require_http_methods(["GET"])
def load_form_template(request, template_slug):
    """Load an existing form template"""
    template = get_object_or_404(FormTemplate, slug=template_slug)

    stages = []
    for stage in template.stages.all():
        fields = []
        for field in stage.fields.all():
            fields.append(
                {
                    "id": field.id,
                    "type": field.field_type,
                    "label": field.label,
                    "placeholder": field.placeholder,
                    "required": field.required,
                    "options": field.options,
                    "fileTypes": field.file_types,
                    "maxFileSize": field.max_file_size,
                    "predefined": field.is_predefined,
                }
            )
        stages.append(
            {
                "id": stage.id,
                "name": stage.name,
                "predefined": stage.is_predefined,
                "fields": fields,
            }
        )

    return JsonResponse(
        {
            "success": True,
            "template": {
                "id": template.id,
                "template_slug": template.slug,
                "name": template.name,
                "description": template.description,
                "is_active": template.is_active,
                "job": template.job_id if template.job else None,
                "stages": stages,
            },
        }
    )


@login_required
@staff_user_required
def form_templates_list(request):
    """List all form templates for the current user"""
    query = request.GET.get("q", "")
    templates = FormTemplate.objects.filter()

    if query:
        templates = templates.filter(
            Q(name__icontains=query) | Q(description__icontains=query)
        )

    templates = templates.order_by("-created_at")
    paginator = Paginator(templates, 10)  # Show 10 templates per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)
    form = FormTemplateForm()
    form.fields["job"].queryset = JobPosting.objects.filter(form_template__isnull=True)
    context = {"templates": page_obj, "query": query, "form": form}
    return render(request, "forms/form_templates_list.html", context)


@login_required
@staff_user_required
def create_form_template(request):
    """Create a new form template"""
    if request.method == "POST":
        form = FormTemplateForm(request.POST)
        if form.is_valid():
            template = form.save(commit=False)
            template.created_by = request.user
            template.save()
            messages.success(
                request, f'Form template "{template.name}" created successfully!'
            )
            return redirect("form_templates_list")
    else:
        form = FormTemplateForm()

    return render(request, "forms/create_form_template.html", {"form": form})


@login_required
@staff_user_required
@require_http_methods(["GET"])
def list_form_templates(request):
    """List all form templates for the current user"""
    templates = FormTemplate.objects.filter().values(
        "id", "name", "description", "created_at", "updated_at"
    )
    return JsonResponse({"success": True, "templates": list(templates)})


@login_required
@staff_user_required
def form_submission_details(request, template_id, slug):
    """Display detailed view of a specific form submission"""
    # Get form template and verify ownership
    template = get_object_or_404(FormTemplate, id=template_id)
    # Get the specific submission
    submission = get_object_or_404(FormSubmission, slug=slug, template=template)

    # Get all stages with their fields
    stages = template.stages.prefetch_related("fields").order_by("order")

    # Get all responses for this submission, ordered by field order
    responses = submission.responses.select_related("field").order_by("field__order")

    # Group responses by stage
    stage_responses = {}
    for stage in stages:
        stage_responses[stage.id] = {
            "stage": stage,
            "responses": responses.filter(field__stage=stage),
        }

    return render(
        request,
        "forms/form_submission_details.html",
        {
            "template": template,
            "submission": submission,
            "stages": stages,
            "responses": responses,
            "stage_responses": stage_responses,
        },
    )
    # return redirect("application_detail", slug=job.slug)

    # return render(
    #     request,
    #     "forms/application_submit_form.html",
    #     {"template_slug": template_slug, "job_id": job_id},
    # )


@login_required
@staff_user_required
@require_http_methods(["DELETE"])
def delete_form_template(request, template_id):
    """Delete a form template"""
    template = get_object_or_404(FormTemplate, id=template_id)
    template.delete()
    return JsonResponse(
        {"success": True, "message": "Form template deleted successfully!"}
    )



def application_submit_form(request, template_slug):
    """Display the form as a step-by-step wizard"""
    if not request.user.is_authenticated:
        return redirect("candidate_signup",slug=template_slug)
    template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True)
    stage = template.stages.filter(name="Contact Information")


    job_id = template.job.internal_job_id
    job = template.job
    is_limit_exceeded = job.is_application_limit_reached
    if is_limit_exceeded:
        messages.error(
            request,
            _(
                "Application limit reached: This job is no longer accepting new applications."
            ),
        )
        return redirect("application_detail", slug=job.slug)
    if job.is_expired:
        messages.error(
            request,
            _(
                "Application deadline passed: This job is no longer accepting new applications."
            ),
        )
        return redirect("application_detail", slug=job.slug)

    return render(
        request,
        "applicant/application_submit_form.html",
        {"template_slug": template_slug, "job_id": job_id},
    )


# def applicant_profile(request):
#     return render(request, "applicant/applicant_profile.html")


@csrf_exempt
@require_POST
def application_submit(request, template_slug):
    """Handle form submission"""
    if not request.user.is_authenticated :# or request.user.user_type != "candidate":
        return JsonResponse({"success": False, "message": "Unauthorized access."})
    template = get_object_or_404(FormTemplate, slug=template_slug)
    job = template.job
    if request.method == "POST":
        try:
            with transaction.atomic():
                job_posting = JobPosting.objects.select_for_update().get(
                    form_template=template
                )

                current_count = job_posting.applications.count()
                if current_count >= job_posting.max_applications:
                    template.is_active = False
                    template.save()
                    return JsonResponse(
                        {
                            "success": False,
                            "message": "Application limit reached for this job.",
                        }
                    )
                submission = FormSubmission.objects.create(template=template,submitted_by=request.user)

            # Process field responses
            for field_id, value in request.POST.items():
                if field_id.startswith("field_"):
                    actual_field_id = field_id.replace("field_", "")
                    try:
                        field = FormField.objects.get(
                            id=actual_field_id, stage__template=template
                        )
                        FieldResponse.objects.create(
                            submission=submission,
                            field=field,
                            value=value if value else None,
                        )
                    except FormField.DoesNotExist:
                        continue

            # Handle file uploads
            for field_id, uploaded_file in request.FILES.items():
                if field_id.startswith("field_"):
                    actual_field_id = field_id.replace("field_", "")
                    try:
                        field = FormField.objects.get(
                            id=actual_field_id, stage__template=template
                        )
                        FieldResponse.objects.create(
                            submission=submission,
                            field=field,
                            uploaded_file=uploaded_file,
                        )
                    except FormField.DoesNotExist:
                        continue
            try:
                # first_name = submission.responses.get(field__label="First Name")
                # last_name = submission.responses.get(field__label="Last Name")
                # email = submission.responses.get(field__label="Email Address")
                # phone = submission.responses.get(field__label="Phone Number")
                # address = submission.responses.get(field__label="Address")
                gpa = submission.responses.get(field__label="GPA")

                resume = submission.responses.get(field__label="Resume Upload")

                submission.applicant_name = (
                    f"{request.user.first_name} {request.user.last_name}"
                )
                submission.applicant_email = request.user.email
                submission.save()
                # time=timezone.now()
                person = request.user.person_profile
                person.gpa = gpa.value if gpa else None
                person.save()
                Application.objects.create(
                    person = person,
                    resume=resume.get_file if resume.is_file else None,
                    job=job,
                )
                return JsonResponse(
                    {
                        "success": True,
                        "message": "Form submitted successfully!",
                        "redirect_url": reverse(
                            "application_success", kwargs={"slug": job.slug}
                        ),
                    }
                )
                # return redirect('application_success',slug=job.slug)

            except Exception as e:
                logger.error(f"Candidate creation failed,{e}")
                pass
            return JsonResponse(
                {
                    "success": True,
                    "message": "Form submitted successfully!",
                    "submission_id": submission.id,
                }
            )
        except Exception as e:
            return JsonResponse({"success": False, "error": str(e)}, status=400)
    else:
        # Handle GET request - this should not happen for form submission
        return JsonResponse(
            {"success": False, "error": "GET method not allowed for form submission"},
            status=405,
        )


@login_required
@staff_user_required
def form_template_submissions_list(request, slug):
    """List all submissions for a specific form template"""
    template = get_object_or_404(FormTemplate, slug=slug)

    submissions = FormSubmission.objects.filter(template=template).order_by(
        "-submitted_at"
    )

    # Pagination
    paginator = Paginator(submissions, 10)  # Show 10 submissions per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    return render(
        request,
        "forms/form_template_submissions_list.html",
        {"template": template, "page_obj": page_obj},
    )


@login_required
@staff_user_required
def form_template_all_submissions(request, template_id):
    """Display all submissions for a form template in table format"""
    template = get_object_or_404(FormTemplate, id=template_id)
    print(template)
    # Get all submissions for this template
    submissions = FormSubmission.objects.filter(template=template).order_by(
        "-submitted_at"
    )

    # Get all fields for this template, ordered by stage and field order
    fields = (
        FormField.objects.filter(stage__template=template)
        .select_related("stage")
        .order_by("stage__order", "order")
    )

    # Pagination
    paginator = Paginator(submissions, 10)  # Show 10 submissions per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    return render(
        request,
        "forms/form_template_all_submissions.html",
        {
            "template": template,
            "page_obj": page_obj,
            "fields": fields,
        },
    )


@login_required
def form_submission_details(request, template_id, slug):
    """Display detailed view of a specific form submission"""
    # Get the form template and verify ownership
    template = get_object_or_404(FormTemplate, id=template_id)
    # Get the specific submission
    submission = get_object_or_404(FormSubmission, slug=slug, template=template)

    # Get all stages with their fields
    stages = template.stages.prefetch_related("fields").order_by("order")

    # Get all responses for this submission, ordered by field order
    responses = submission.responses.select_related("field").order_by("field__order")

    # Group responses by stage
    stage_responses = {}
    for stage in stages:
        stage_responses[stage.id] = {
            "stage": stage,
            "responses": responses.filter(field__stage=stage),
        }

    return render(
        request,
        "forms/form_submission_details.html",
        {
            "template": template,
            "submission": submission,
            "stages": stages,
            "responses": responses,
            "stage_responses": stage_responses,
        },
    )


def _handle_get_request(request, slug, job):
    """
    Handles GET requests, setting up forms and restoring candidate selections
    from the session for persistence.
    """
    SESSION_KEY = f"schedule_candidate_ids_{slug}"

    form = InterviewScheduleForm(slug=slug)
    # break_formset = BreakTimeFormSet(prefix='breaktime')

    selected_ids = []

    # 1. Capture IDs from HTMX request and store in session (when first clicked)
    if "HX-Request" in request.headers:
        candidate_ids = request.GET.getlist("candidate_ids")

        if candidate_ids:
            request.session[SESSION_KEY] = candidate_ids
        selected_ids = candidate_ids

    # 2. Restore IDs from session (on refresh or navigation)
    if not selected_ids:
        selected_ids = request.session.get(SESSION_KEY, [])

    # 3. Use the list of IDs to initialize the form
    if selected_ids:
        candidates_to_load = Application.objects.filter(pk__in=selected_ids)
        print(candidates_to_load)
        form.initial["applications"] = candidates_to_load

    return render(
        request,
        "interviews/schedule_interviews.html",
        {"form": form, "job": job},
    )



def _handle_preview_submission(request, slug, job):
    """
    Handles the initial POST request (Preview Schedule).
    Validates forms, calculates slots, saves data to session, and renders preview.
    """
    SESSION_DATA_KEY = "interview_schedule_data"
    form = InterviewScheduleForm(slug, request.POST)
    # break_formset = BreakTimeFormSet(request.POST,prefix='breaktime')

    if form.is_valid():
        # Get the form data
        applications = form.cleaned_data["applications"]
        start_date = form.cleaned_data["start_date"]
        end_date = form.cleaned_data["end_date"]
        working_days = form.cleaned_data["working_days"]
        start_time = form.cleaned_data["start_time"]
        end_time = form.cleaned_data["end_time"]
        interview_duration = form.cleaned_data["interview_duration"]
        buffer_time = form.cleaned_data["buffer_time"]
        break_start_time = form.cleaned_data["break_start_time"]
        break_end_time = form.cleaned_data["break_end_time"]
        schedule_interview_type=form.cleaned_data["schedule_interview_type"]
        # Process break times
        # breaks = []
        # for break_form in break_formset:
        #     print(break_form.cleaned_data)
        #     if break_form.cleaned_data and not break_form.cleaned_data.get("DELETE"):
        #         breaks.append(
        #             {
        #                 "start_time": break_form.cleaned_data["start_time"].strftime("%H:%M:%S"),
        #                 "end_time": break_form.cleaned_data["end_time"].strftime("%H:%M:%S"),
        #             }
        #         )

        # Create a temporary schedule object (not saved to DB)
        temp_schedule = InterviewSchedule(
            job=job,
            start_date=start_date,
            end_date=end_date,
            working_days=working_days,
            start_time=start_time,
            end_time=end_time,
            interview_duration=interview_duration,
            buffer_time=buffer_time or 5,
            break_start_time=break_start_time or None,
            break_end_time=break_end_time or None,
        )

        # Get available slots (temp_breaks logic moved into get_available_time_slots if needed)
        available_slots = get_available_time_slots(temp_schedule)

        if len(available_slots) < len(applications):
            messages.error(
                request,
                f"Not enough available slots. Required: {len(applications)}, Available: {len(available_slots)}",
            )
            return render(
                request,
                "interviews/schedule_interviews.html",
                {"form": form, "job": job},
            )

        # Create a preview schedule
        preview_schedule = []
        for i, application in enumerate(applications):
            slot = available_slots[i]
            preview_schedule.append(
                {"application": application, "date": slot["date"], "time": slot["time"]}
            )

        # Save the form data to session for later use
        schedule_data = {
            "start_date": start_date.isoformat(),
            "end_date": end_date.isoformat(),
            "working_days": working_days,
            "start_time": start_time.isoformat(),
            "end_time": end_time.isoformat(),
            "interview_duration": interview_duration,
            "buffer_time": buffer_time,
            "break_start_time": break_start_time.isoformat() if break_start_time else None,
            "break_end_time": break_end_time.isoformat() if break_end_time else None,
            "candidate_ids": [c.id for c in applications],
            "schedule_interview_type":schedule_interview_type

        }
        request.session[SESSION_DATA_KEY] = schedule_data

        # Render the preview page
        return render(
            request,
            "interviews/preview_schedule.html",
            {
                "job": job,
                "schedule": preview_schedule,
                "start_date": start_date,
                "end_date": end_date,
                "working_days": working_days,
                "start_time": start_time,
                "end_time": end_time,
                "break_start_time": break_start_time,
                "break_end_time": break_end_time,
                "interview_duration": interview_duration,
                "buffer_time": buffer_time,
                "schedule_interview_type":schedule_interview_type,
                "form":OnsiteLocationForm()
            },
        )
    else:
        # Re-render the form if validation fails
        return render(
            request,
            "interviews/schedule_interviews.html",
            {"form": form, "job": job},
        )



def _handle_confirm_schedule(request, slug, job):
    """
    Handles the final POST request (Confirm Schedule).
    Creates the main schedule record and queues individual interviews asynchronously.
    """

    SESSION_DATA_KEY = "interview_schedule_data"
    SESSION_ID_KEY = f"schedule_candidate_ids_{slug}"

    # 1. Get schedule data from session
    schedule_data = request.session.get(SESSION_DATA_KEY)

    if not schedule_data:
        messages.error(request, "Session expired. Please try again.")
        return redirect("schedule_interviews", slug=slug)

    # 2. Create the Interview Schedule (Parent Record)
    try:
        # Handle break times: If they exist, convert them; otherwise, pass None.
        break_start = schedule_data.get("break_start_time")
        break_end = schedule_data.get("break_end_time")

        schedule = InterviewSchedule.objects.create(
            job=job,
            created_by=request.user,
            start_date=datetime.fromisoformat(schedule_data["start_date"]).date(),
            end_date=datetime.fromisoformat(schedule_data["end_date"]).date(),
            working_days=schedule_data["working_days"],
            start_time=time.fromisoformat(schedule_data["start_time"]),
            end_time=time.fromisoformat(schedule_data["end_time"]),
            interview_duration=schedule_data["interview_duration"],
            buffer_time=schedule_data["buffer_time"],
            # Convert time strings to time objects only if they exist and handle None gracefully
            break_start_time=time.fromisoformat(break_start) if break_start else None,
            break_end_time=time.fromisoformat(break_end) if break_end else None,
            schedule_interview_type=schedule_data.get("schedule_interview_type")
        )
    except Exception as e:
        # Clear data on failure to prevent stale data causing repeated errors
        messages.error(request, f"Error creating schedule: {e}")
        if SESSION_ID_KEY in request.session: del request.session[SESSION_ID_KEY]
        if SESSION_DATA_KEY in request.session: del request.session[SESSION_DATA_KEY]
        return redirect("schedule_interviews", slug=slug)

    # 3. Setup candidates and get slots
    candidates = Application.objects.filter(id__in=schedule_data["candidate_ids"])
    schedule.applications.set(candidates)
    available_slots = get_available_time_slots(schedule)

    # 4. Handle Remote/Onsite logic
    if schedule_data.get("schedule_interview_type") == 'Remote':
        # ... (Remote logic remains unchanged)
        queued_count = 0
        for i, candidate in enumerate(candidates):
            if i < len(available_slots):
                slot = available_slots[i]

            async_task(
                "recruitment.tasks.create_interview_and_meeting",
                candidate.pk, job.pk, schedule.pk, slot["date"], slot["time"], schedule.interview_duration,
            )
            queued_count += 1

        messages.success(
            request,
            f"Schedule successfully created. Queued {queued_count} interviews to be booked asynchronously. Check back in a moment!",
        )

        if SESSION_DATA_KEY in request.session: del request.session[SESSION_DATA_KEY]
        if SESSION_ID_KEY in request.session: del request.session[SESSION_ID_KEY]

        return redirect("job_detail", slug=slug)

    elif schedule_data.get("schedule_interview_type") == 'Onsite':
        print("inside...")

        if request.method == 'POST':
            form = OnsiteLocationForm(request.POST)

            if form.is_valid():

                if not available_slots:
                    messages.error(request, "No available slots found for the selected schedule range.")
                    return render(request, 'interviews/onsite_location_form.html', {'form': form, 'schedule': schedule, 'job': job})

                # Extract common location data from the form
                physical_address = form.cleaned_data['physical_address']
                room_number = form.cleaned_data['room_number']
                topic=form.cleaned_data['topic']


                try:
                    # 1. Iterate over candidates and create a NEW Location object for EACH
                    for i, candidate in enumerate(candidates):
                        if i < len(available_slots):
                            slot = available_slots[i]


                            location_start_dt = datetime.combine(slot['date'], schedule.start_time)

                            # --- CORE FIX: Create a NEW Location object inside the loop ---
                            onsite_location = OnsiteLocationDetails.objects.create(
                                start_time=location_start_dt,
                                duration=schedule.interview_duration,
                                physical_address=physical_address,
                                room_number=room_number,
                                location_type="Onsite",
                                topic=topic

                            )

                            # 2. Create the ScheduledInterview, linking the unique location
                            ScheduledInterview.objects.create(
                                application=candidate,
                                job=job,
                                schedule=schedule,
                                interview_date=slot['date'],
                                interview_time=slot['time'],
                                interview_location=onsite_location,
                            )

                    messages.success(
                        request,
                        f"Onsite schedule interviews created successfully for {len(candidates)} candidates."
                    )

                    # Clear session data keys upon successful completion
                    if SESSION_DATA_KEY in request.session: del request.session[SESSION_DATA_KEY]
                    if SESSION_ID_KEY in request.session: del request.session[SESSION_ID_KEY]

                    return redirect('job_detail', slug=job.slug)

                except Exception as e:
                    messages.error(request, f"Error creating onsite location/interviews: {e}")
                    # On failure, re-render the form with the error and ensure 'job' is present
                    return render(request, 'interviews/onsite_location_form.html', {'form': form, 'schedule': schedule, 'job': job})

            else:
                # Form is invalid, re-render with errors
                # Ensure 'job' is passed to prevent NoReverseMatch
                return render(request, 'interviews/onsite_location_form.html', {'form': form, 'schedule': schedule, 'job': job})

        else:
            # For a GET request
            form = OnsiteLocationForm()

            return render(request, 'interviews/onsite_location_form.html', {'form': form, 'schedule': schedule, 'job': job})



def schedule_interviews_view(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    if request.method == "POST":
        # return _handle_confirm_schedule(request, slug, job)
        return _handle_preview_submission(request, slug, job)
    else:
        return _handle_get_request(request, slug, job)


def confirm_schedule_interviews_view(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    if request.method == "POST":
        return _handle_confirm_schedule(request, slug, job)


@staff_user_required
def candidate_screening_view(request, slug):
    """
    Manage candidate tiers and stage transitions
    """
    job = get_object_or_404(JobPosting, slug=slug)
    candidates = job.screening_candidates

    # Get filter parameters
    min_ai_score_str = request.GET.get("min_ai_score")
    min_experience_str = request.GET.get("min_experience")
    screening_rating = request.GET.get("screening_rating")
    tier1_count_str = request.GET.get("tier1_count")
    gpa = request.GET.get("GPA")

    try:
        # Check if the string value exists and is not an empty string before conversion
        if min_ai_score_str:
            min_ai_score = int(min_ai_score_str)
        else:
            min_ai_score = 0

        if min_experience_str:
            min_experience = float(min_experience_str)
        else:
            min_experience = 0

        if tier1_count_str:
            tier1_count = int(tier1_count_str)
        else:
            tier1_count = 0

        if gpa:
            gpa = float(gpa)
        else:
            gpa = 0

    except ValueError:
        # This catches if the user enters non-numeric text (e.g., "abc")
        min_ai_score = 0
        min_experience = 0
        tier1_count = 0
        gpa = 0

    # Apply filters
    if min_ai_score > 0:
        candidates = candidates.filter(
            ai_analysis_data__analysis_data__match_score__gte=min_ai_score
        )

    if min_experience > 0:
        candidates = candidates.filter(
            ai_analysis_data__analysis_data__years_of_experience__gte=min_experience
        )

    if screening_rating:
        candidates = candidates.filter(
            ai_analysis_data__analysis_data__screening_stage_rating=screening_rating
        )
    if gpa:
        candidates = candidates.filter(
            person__gpa__gt= gpa
        )
        print(candidates)

    if tier1_count > 0:
        candidates = candidates[:tier1_count]

    context = {
        "job": job,
        "candidates": candidates,
        "min_ai_score": min_ai_score,
        "min_experience": min_experience,
        "screening_rating": screening_rating,
        "tier1_count": tier1_count,
        "gpa": gpa,
        "current_stage": "Applied",
    }

    return render(request, "recruitment/candidate_screening_view.html", context)


@staff_user_required
def candidate_exam_view(request, slug):
    """
    Manage candidate tiers and stage transitions
    """
    job = get_object_or_404(JobPosting, slug=slug)
    context = {"job": job, "candidates": job.exam_candidates, "current_stage": "Exam"}
    return render(request, "recruitment/candidate_exam_view.html", context)


@staff_user_required
def update_candidate_exam_status(request, slug):
    candidate = get_object_or_404(Application, slug=slug)
    if request.method == "POST":
        form = CandidateExamDateForm(request.POST, instance=candidate)
        if form.is_valid():
            form.save()
            return redirect("candidate_exam_view", slug=candidate.job.slug)
    else:
        form = CandidateExamDateForm(request.POST, instance=candidate)
    return render(
        request,
        "includes/candidate_exam_status_form.html",
        {"candidate": candidate, "form": form},
    )


@staff_user_required
def bulk_update_candidate_exam_status(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    status = request.headers.get("status")
    if status:
        for candidate in get_candidates_from_request(request):
            try:
                if status == "pass":
                    candidate.exam_status = "Passed"
                    candidate.stage = "Interview"
                else:
                    candidate.exam_status = "Failed"
                candidate.save()
            except Exception as e:
                print(e)
        messages.success(request, f"Updated exam status selected candidates")
    return redirect("candidate_exam_view", slug=job.slug)


def candidate_criteria_view_htmx(request, pk):
    candidate = get_object_or_404(Application, pk=pk)
    return render(
        request, "includes/candidate_modal_body.html", {"candidate": candidate}
    )


@staff_user_required
def candidate_set_exam_date(request, slug):
    candidate = get_object_or_404(Application, slug=slug)
    candidate.exam_date = timezone.now()
    candidate.save()
    messages.success(
        request, f"Set exam date for {candidate.name} to {candidate.exam_date}"
    )
    return redirect("candidate_screening_view", slug=candidate.job.slug)


@staff_user_required
def candidate_update_status(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)
    mark_as = request.POST.get("mark_as")
    if mark_as != "----------":
        candidate_ids = request.POST.getlist("candidate_ids")
        print(candidate_ids)
        if c := Application.objects.filter(pk__in=candidate_ids):
            if mark_as == "Exam":
                print("exam")
                c.update(
                    exam_date=timezone.now(),
                    interview_date=None,
                    offer_date=None,
                    hired_date=None,
                    stage=mark_as,
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview","Document Review", "Offer"]
                    else "Applicant",
                )
            elif mark_as == "Interview":
                # interview_date update when scheduling the interview
                print("interview")
                c.update(
                    stage=mark_as,
                    offer_date=None,
                    hired_date=None,
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview", "Document Review","Offer"]
                    else "Applicant",
                )
            elif mark_as == "Document Review":
                print("document review")
                c.update(
                    stage=mark_as,
                    offer_date=None,
                    hired_date=None,
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview", "Document Review","Offer"]
                    else "Applicant",
                )
            elif mark_as == "Offer":
                print("offer")
                c.update(
                    stage=mark_as,
                    offer_date=timezone.now(),
                    hired_date=None,
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview", "Document Review","Offer"]
                    else "Applicant",
                )
            elif mark_as == "Hired":
                print("hired")
                c.update(
                    stage=mark_as,
                    hired_date=timezone.now(),
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview", "Offer"]
                    else "Applicant",
                )
            else:
                print("rejected")
                c.update(
                    stage=mark_as,
                    exam_date=None,
                    interview_date=None,
                    offer_date=None,
                    hired_date=None,
                    applicant_status="Candidate"
                    if mark_as in ["Exam", "Interview", "Offer"]
                    else "Applicant",
                )

        messages.success(request, f"Candidates Updated")
    response = HttpResponse(redirect("candidate_screening_view", slug=job.slug))
    response.headers["HX-Refresh"] = "true"
    return response


@staff_user_required
def candidate_interview_view(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)


    context = {
        "job": job,
        "candidates": job.interview_candidates,
        "current_stage": "Interview",

    }
    return render(request, "recruitment/candidate_interview_view.html", context)




@staff_user_required
def candidate_document_review_view(request, slug):
    """
    Document review view for candidates after interview stage and before offer stage
    """
    job = get_object_or_404(JobPosting, slug=slug)

    # Get candidates from Interview stage who need document review
    candidates = job.document_review_candidates.select_related('person')
    print(candidates)
    # Get search query for filtering
    search_query = request.GET.get('q', '')
    if search_query:
        candidates = candidates.filter(
            Q(person__first_name__icontains=search_query) |
            Q(person__last_name__icontains=search_query) |
            Q(person__email__icontains=search_query)
        )

    context = {
        "job": job,
        "candidates": candidates,
        "current_stage": "Document Review",
        "search_query": search_query,
    }
    return render(request, "recruitment/candidate_document_review_view.html", context)


@staff_user_required
def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_id)
    meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
    form = ZoomMeetingForm(instance=meeting)

    if request.method == "POST":
        form = ZoomMeetingForm(request.POST, instance=meeting)
        if form.is_valid():
            instance = form.save(commit=False)
            updated_data = {
                "topic": instance.topic,
                "start_time": instance.start_time.isoformat() + "Z",
                "duration": instance.duration,
            }
            if instance.start_time < timezone.now():
                messages.error(request, "Start time must be in the future.")
                return redirect(
                    "reschedule_meeting_for_candidate",
                    slug=job.slug,
                    candidate_id=candidate_id,
                    meeting_id=meeting_id,
                )

            result = update_meeting(instance, updated_data)

            if result["status"] == "success":
                messages.success(request, result["message"])
            else:
                messages.error(request, result["message"])
            return redirect(
                reverse("candidate_interview_view", kwargs={"slug": job.slug})
            )

    context = {"job": job, "candidate": candidate, "meeting": meeting, "form": form}
    return render(request, "meetings/reschedule_meeting.html", context)


@staff_user_required
def delete_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_pk)
    meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
    if request.method == "POST":
        result = delete_zoom_meeting(meeting.meeting_id)
        if (
            result["status"] == "success"
            or "Meeting does not exist" in result["details"]["message"]
        ):
            meeting.delete()
            messages.success(request, "Meeting deleted successfully")
        else:
            messages.error(request, result["message"])
        return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))

    context = {
        "job": job,
        "candidate": candidate,
        "meeting": meeting,
        "delete_url": reverse(
            "delete_meeting_for_candidate",
            kwargs={
                "slug": job.slug,
                "candidate_pk": candidate_pk,
                "meeting_id": meeting_id,
            },
        ),
    }
    return render(request, "meetings/delete_meeting_form.html", context)

@staff_user_required
def delete_zoom_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
    """
    Deletes a specific Zoom (Remote) meeting instance.
    The ZoomMeetingDetails object inherits from InterviewLocation,
    which is linked to ScheduledInterview. Deleting the subclass
    should trigger CASCADE/SET_NULL correctly on the FK chain.
    """
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_pk)

    # Target the specific Zoom meeting details instance
    meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)

    if request.method == "POST":
        # 1. Attempt to delete the meeting from the external Zoom API
        result = delete_zoom_meeting(meeting.meeting_id)

        # 2. Check for success OR if the meeting was already deleted externally
        if (
            result["status"] == "success"
            or "Meeting does not exist" in result["details"]["message"]
        ):
            # 3. Delete the local Django object. This will delete the base
            #    InterviewLocation object and update the ScheduledInterview FK.
            meeting.delete()
            messages.success(request, f"Remote meeting for {candidate.name} deleted successfully.")
        else:
            messages.error(request, result["message"])

        return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))

    context = {
        "job": job,
        "candidate": candidate,
        "meeting": meeting,
        "location_type": "Remote",
        "delete_url": reverse(
            "delete_remote_meeting_for_candidate", # Use the specific new URL name
            kwargs={
                "slug": job.slug,
                "candidate_pk": candidate_pk,
                "meeting_id": meeting_id,
            },
        ),
    }
    return render(request, "meetings/delete_meeting_form.html", context)

@staff_user_required
def interview_calendar_view(request, slug):
    job = get_object_or_404(JobPosting, slug=slug)

    # Get all scheduled interviews for this job
    scheduled_interviews = ScheduledInterview.objects.filter(job=job).select_related(
        "applicaton", "zoom_meeting"
    )

    # Convert interviews to calendar events
    events = []
    for interview in scheduled_interviews:
        # Create start datetime
        start_datetime = datetime.combine(
            interview.interview_date, interview.interview_time
        )

        # Calculate end datetime based on interview duration
        duration = interview.zoom_meeting.duration if interview.zoom_meeting else 60
        end_datetime = start_datetime + timedelta(minutes=duration)

        # Determine event color based on status
        color = "#00636e"  # Default color
        if interview.status == "confirmed":
            color = "#00a86b"  # Green for confirmed
        elif interview.status == "cancelled":
            color = "#e74c3c"  # Red for cancelled
        elif interview.status == "completed":
            color = "#95a5a6"  # Gray for completed

        events.append(
            {
                "title": f"Interview: {interview.candidate.name}",
                "start": start_datetime.isoformat(),
                "end": end_datetime.isoformat(),
                "url": f"{request.path}interview/{interview.id}/",
                "color": color,
                "extendedProps": {
                    "candidate": interview.candidate.name,
                    "email": interview.candidate.email,
                    "status": interview.status,
                    "meeting_id": interview.zoom_meeting.meeting_id
                    if interview.zoom_meeting
                    else None,
                    "join_url": interview.zoom_meeting.join_url
                    if interview.zoom_meeting
                    else None,
                },
            }
        )

    context = {
        "job": job,
        "events": events,
        "calendar_color": "#00636e",
    }

    return render(request, "recruitment/interview_calendar.html", context)


@staff_user_required
def interview_detail_view(request, slug, interview_id):
    job = get_object_or_404(JobPosting, slug=slug)
    interview = get_object_or_404(ScheduledInterview, id=interview_id, job=job)

    context = {
        "job": job,
        "interview": interview,
    }

    return render(request, "recruitment/interview_detail.html", context)


# Candidate Meeting Scheduling/Rescheduling Views
@require_POST
def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
    """
    Handle POST request to schedule a Zoom meeting for a candidate via HTMX.
    Returns JSON response for modal update.
    """
    job = get_object_or_404(JobPosting, slug=job_slug)
    candidate = get_object_or_404(Application, pk=candidate_pk, job=job)

    topic = f"Interview: {job.title} with {candidate.name}"
    start_time_str = request.POST.get("start_time")
    duration = int(request.POST.get("duration", 60))

    if not start_time_str:
        return JsonResponse(
            {"success": False, "error": "Start time is required."}, status=400
        )

    try:
        # Parse datetime from datetime-local input (YYYY-MM-DDTHH:MM)
        # This will be in server's timezone, create_zoom_meeting will handle UTC conversion
        naive_start_time = datetime.fromisoformat(start_time_str)
        # Ensure it's timezone-aware if your system requires it, or let create_zoom_meeting handle it.
        # For simplicity, assuming create_zoom_meeting handles naive datetimes or they are in UTC.
        # If start_time is expected to be in a specific timezone, convert it here.
        # e.g., start_time = timezone.make_aware(naive_start_time, timezone.get_current_timezone())
        start_time = naive_start_time  # Or timezone.make_aware(naive_start_time)
    except ValueError:
        return JsonResponse(
            {"success": False, "error": "Invalid date/time format for start time."},
            status=400,
        )

    if start_time <= timezone.now():
        return JsonResponse(
            {"success": False, "error": "Start time must be in the future."}, status=400
        )

    result = create_zoom_meeting(topic=topic, start_time=start_time, duration=duration)

    if result["status"] == "success":
        zoom_meeting_details = result["meeting_details"]
        zoom_meeting = ZoomMeetingDetails.objects.create(
            topic=topic,
            start_time=start_time,  # Store in local timezone
            duration=duration,
            meeting_id=zoom_meeting_details["meeting_id"],
            join_url=zoom_meeting_details["join_url"],
            password=zoom_meeting_details["password"],
            # host_email=zoom_meeting_details["host_email"],
            status=result["zoom_gateway_response"].get("status", "waiting"),
            zoom_gateway_response=result["zoom_gateway_response"],
        )
        scheduled_interview = ScheduledInterview.objects.create(
            candidate=candidate,
            job=job,
            zoom_meeting=zoom_meeting,
            interview_date=start_time.date(),
            interview_time=start_time.time(),
            status="scheduled",  # Or 'confirmed' depending on your workflow
        )
        messages.success(request, f"Meeting scheduled with {candidate.name}.")

        # Return updated table row or a success message
        # For HTMX, you might want to return a fragment of the updated table
        # For now, returning JSON to indicate success and close modal
        return JsonResponse(
            {
                "success": True,
                "message": "Meeting scheduled successfully!",
                "join_url": zoom_meeting.join_url,
                "meeting_id": zoom_meeting.meeting_id,
                "candidate_name": candidate.name,
                "interview_datetime": start_time.strftime("%Y-%m-%d %H:%M"),
            }
        )
    else:
        messages.error(request, result["message"])
        return JsonResponse({"success": False, "error": result["message"]}, status=400)


def schedule_candidate_meeting(request, job_slug, candidate_pk):
    """
    GET: Render modal form to schedule a meeting. (For HTMX)
    POST: Handled by api_schedule_candidate_meeting.
    """
    job = get_object_or_404(JobPosting, slug=job_slug)
    candidate = get_object_or_404(Application, pk=candidate_pk, job=job)

    if request.method == "POST":
        return api_schedule_candidate_meeting(request, job_slug, candidate_pk)

    # GET request - render the form snippet for HTMX
    context = {
        "job": job,
        "candidate": candidate,
        "action_url": reverse(
            "api_schedule_candidate_meeting",
            kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
        ),
        "scheduled_interview": None,  # Explicitly None for schedule
    }
    # Render just the form part, or the whole modal body content
    return render(request, "includes/meeting_form.html", context)


@require_http_methods(["GET", "POST"])
def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
    """
    Handles GET to render form and POST to process scheduling.
    """
    job = get_object_or_404(JobPosting, slug=job_slug)
    candidate = get_object_or_404(Application, pk=candidate_pk, job=job)

    if request.method == "GET":
        # This GET is for HTMX to fetch the form
        context = {
            "job": job,
            "candidate": candidate,
            "action_url": reverse(
                "api_schedule_candidate_meeting",
                kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
            ),
            "scheduled_interview": None,
        }
        return render(request, "includes/meeting_form.html", context)

    # POST logic (remains the same)
    topic = f"Interview: {job.title} with {candidate.name}"
    start_time_str = request.POST.get("start_time")
    duration = int(request.POST.get("duration", 60))

    if not start_time_str:
        return JsonResponse(
            {"success": False, "error": "Start time is required."}, status=400
        )

    try:
        naive_start_time = datetime.fromisoformat(start_time_str)
        start_time = naive_start_time
    except ValueError:
        return JsonResponse(
            {"success": False, "error": "Invalid date/time format for start time."},
            status=400,
        )

    if start_time <= timezone.now():
        return JsonResponse(
            {"success": False, "error": "Start time must be in the future."}, status=400
        )

    result = create_zoom_meeting(topic=topic, start_time=start_time, duration=duration)

    if result["status"] == "success":
        zoom_meeting_details = result["meeting_details"]
        zoom_meeting = ZoomMeetingDetails.objects.create(
            topic=topic,
            start_time=start_time,
            duration=duration,
            meeting_id=zoom_meeting_details["meeting_id"],
            join_url=zoom_meeting_details["join_url"],
            password=zoom_meeting_details["password"],
            host_email=zoom_meeting_details["host_email"],
            status=result["zoom_gateway_response"].get("status", "waiting"),
            zoom_gateway_response=result["zoom_gateway_response"],
        )
        scheduled_interview = ScheduledInterview.objects.create(
            candidate=candidate,
            job=job,
            zoom_meeting=zoom_meeting,
            interview_date=start_time.date(),
            interview_time=start_time.time(),
            status="scheduled",
        )
        messages.success(request, f"Meeting scheduled with {candidate.name}.")
        return JsonResponse(
            {
                "success": True,
                "message": "Meeting scheduled successfully!",
                "join_url": zoom_meeting.join_url,
                "meeting_id": zoom_meeting.meeting_id,
                "candidate_name": candidate.name,
                "interview_datetime": start_time.strftime("%Y-%m-%d %H:%M"),
            }
        )
    else:
        messages.error(request, result["message"])
        return JsonResponse({"success": False, "error": result["message"]}, status=400)


@require_http_methods(["GET", "POST"])
def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
    """
    Handles GET to render form and POST to process rescheduling.
    """
    job = get_object_or_404(JobPosting, slug=job_slug)
    scheduled_interview = get_object_or_404(
        ScheduledInterview.objects.select_related("zoom_meeting"),
        pk=interview_pk,
        application__pk=candidate_pk,
        job=job,
    )
    zoom_meeting = scheduled_interview.zoom_meeting

    if request.method == "GET":
        # This GET is for HTMX to fetch the form
        initial_data = {
            "topic": zoom_meeting.topic,
            "start_time": zoom_meeting.start_time.strftime("%Y-%m-%dT%H:%M"),
            "duration": zoom_meeting.duration,
        }
        context = {
            "job": job,
            "candidate": scheduled_interview.application,
            "scheduled_interview": scheduled_interview,  # Pass for conditional logic in template
            "initial_data": initial_data,
            "action_url": reverse(
                "api_reschedule_candidate_meeting",
                kwargs={
                    "job_slug": job_slug,
                    "candidate_pk": candidate_pk,
                    "interview_pk": interview_pk,
                },
            ),
        }
        return render(request, "includes/meeting_form.html", context)

    # POST logic (remains the same)
    new_start_time_str = request.POST.get("start_time")
    new_duration = int(request.POST.get("duration", zoom_meeting.duration))

    if not new_start_time_str:
        return JsonResponse(
            {"success": False, "error": "New start time is required."}, status=400
        )

    try:
        naive_new_start_time = datetime.fromisoformat(new_start_time_str)
        new_start_time = naive_new_start_time
    except ValueError:
        return JsonResponse(
            {"success": False, "error": "Invalid date/time format for new start time."},
            status=400,
        )

    if new_start_time <= timezone.now():
        return JsonResponse(
            {"success": False, "error": "Start time must be in the future."}, status=400
        )

    updated_data = {
        "topic": f"Interview: {job.title} with {scheduled_interview.candidate.name}",
        "start_time": new_start_time.isoformat() + "Z",
        "duration": new_duration,
    }

    result = update_zoom_meeting(zoom_meeting.meeting_id, updated_data)

    if result["status"] == "success":
        details_result = get_zoom_meeting_details(zoom_meeting.meeting_id)
        if details_result["status"] == "success":
            updated_zoom_details = details_result["meeting_details"]
            zoom_meeting.topic = updated_zoom_details.get("topic", zoom_meeting.topic)
            zoom_meeting.start_time = new_start_time
            zoom_meeting.duration = new_duration
            zoom_meeting.join_url = updated_zoom_details.get(
                "join_url", zoom_meeting.join_url
            )
            zoom_meeting.password = updated_zoom_details.get(
                "password", zoom_meeting.password
            )
            zoom_meeting.status = updated_zoom_details.get(
                "status", zoom_meeting.status
            )
            zoom_meeting.zoom_gateway_response = updated_zoom_details
            zoom_meeting.save()

            scheduled_interview.interview_date = new_start_time.date()
            scheduled_interview.interview_time = new_start_time.time()
            scheduled_interview.status = "rescheduled"
            scheduled_interview.save()
            messages.success(
                request,
                f"Meeting for {scheduled_interview.candidate.name} rescheduled.",
            )
        else:
            logger.warning(
                f"Zoom meeting {zoom_meeting.meeting_id} updated, but failed to fetch latest details."
            )
            zoom_meeting.start_time = new_start_time
            zoom_meeting.duration = new_duration
            zoom_meeting.save()
            scheduled_interview.interview_date = new_start_time.date()
            scheduled_interview.interview_time = new_start_time.time()
            scheduled_interview.save()
            messages.success(
                request,
                f"Meeting for {scheduled_interview.candidate.name} rescheduled. (Note: Could not refresh all details from Zoom.)",
            )

        return JsonResponse(
            {
                "success": True,
                "message": "Meeting rescheduled successfully!",
                "join_url": zoom_meeting.join_url,
                "new_interview_datetime": new_start_time.strftime("%Y-%m-%d %H:%M"),
            }
        )
    else:
        messages.error(request, result["message"])
        return JsonResponse({"success": False, "error": result["message"]}, status=400)


# The original schedule_candidate_meeting and reschedule_candidate_meeting (without api_ prefix)
# can be removed if their only purpose was to be called by the JS onclicks.
# If they were intended for other direct URL access, they can be kept as simple redirects
# or wrappers to the api_ versions.
# For now, let's assume the api_ versions are the primary ones for HTMX.


def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
    """
    Handles GET to display a form for rescheduling a meeting.
    Handles POST to process the rescheduling of a meeting.
    """
    job = get_object_or_404(JobPosting, slug=job_slug)
    application = get_object_or_404(Application, pk=candidate_pk, job=job)
    scheduled_interview = get_object_or_404(
        ScheduledInterview.objects.select_related("zoom_meeting"),
        pk=interview_pk,
        application=application,
        job=job,
    )
    zoom_meeting = scheduled_interview.zoom_meeting

    # Determine if the candidate has other future meetings
    # This helps in providing context in the template
    # Note: This checks for *any* future meetings for the candidate, not just the one being rescheduled.
    # If candidate.has_future_meeting is True, it implies they have at least one other upcoming meeting,
    # or the specific meeting being rescheduled is itself in the future.
    # We can refine this logic if needed, e.g., check for meetings *other than* the current `interview_pk`.
    has_other_future_meetings = application.has_future_meeting
    # More precise check: if the current meeting being rescheduled is in the future, then by definition
    # the candidate will have a future meeting (this one). The UI might want to know if there are *others*.
    # For now, `candidate.has_future_meeting` is a good general indicator.

    if request.method == "POST":
        form = ZoomMeetingForm(request.POST)
        if form.is_valid():
            new_topic = form.cleaned_data.get("topic")
            new_start_time = form.cleaned_data.get("start_time")
            new_duration = form.cleaned_data.get("duration")

            # Use a default topic if not provided, keeping with the original structure
            if not new_topic:
                new_topic = f"Interview: {job.title} with {application.name}"

            # Ensure new_start_time is in the future
            if new_start_time <= timezone.now():
                messages.error(request, "Start time must be in the future.")
                # Re-render form with error and initial data
                return render(
                    request,
                    "recruitment/schedule_meeting_form.html",
                    {  # Reusing the same form template
                        "form": form,
                        "job": job,
                        "application": application,
                        "scheduled_interview": scheduled_interview,
                        "initial_topic": new_topic,
                        "initial_start_time": new_start_time.strftime("%Y-%m-%dT%H:%M")
                        if new_start_time
                        else "",
                        "initial_duration": new_duration,
                        "action_url": reverse(
                            "reschedule_candidate_meeting",
                            kwargs={
                                "job_slug": job_slug,
                                "candidate_pk": candidate_pk,
                                "interview_pk": interview_pk,
                            },
                        ),
                        "has_future_meeting": has_other_future_meetings,  # Pass status for template
                    },
                )

            # Prepare data for Zoom API update
            # The update_zoom_meeting expects start_time as ISO string with 'Z'
            zoom_update_data = {
                "topic": new_topic,
                "start_time": new_start_time.isoformat() + "Z",
                "duration": new_duration,
            }

            # Update Zoom meeting using utility function
            zoom_update_result = update_zoom_meeting(
                zoom_meeting.meeting_id, zoom_update_data
            )

            if zoom_update_result["status"] == "success":
                # Fetch the latest details from Zoom after successful update
                details_result = get_zoom_meeting_details(zoom_meeting.meeting_id)

                if details_result["status"] == "success":
                    updated_zoom_details = details_result["meeting_details"]
                    # Update local ZoomMeeting record
                    zoom_meeting.topic = updated_zoom_details.get("topic", new_topic)
                    zoom_meeting.start_time = (
                        new_start_time  # Store the original datetime
                    )
                    zoom_meeting.duration = new_duration
                    zoom_meeting.join_url = updated_zoom_details.get(
                        "join_url", zoom_meeting.join_url
                    )
                    zoom_meeting.password = updated_zoom_details.get(
                        "password", zoom_meeting.password
                    )
                    zoom_meeting.status = updated_zoom_details.get(
                        "status", zoom_meeting.status
                    )
                    zoom_meeting.zoom_gateway_response = details_result.get(
                        "meeting_details"
                    )
                    zoom_meeting.save()

                    # Update ScheduledInterview record
                    scheduled_interview.interview_date = new_start_time.date()
                    scheduled_interview.interview_time = new_start_time.time()
                    scheduled_interview.status = (
                        "rescheduled"  # Or 'scheduled' if you prefer
                    )
                    scheduled_interview.save()
                    messages.success(
                        request,
                        f"Meeting for {application.name} rescheduled successfully.",
                    )
                else:
                    # If fetching details fails, update with form data and log a warning
                    logger.warning(
                        f"Successfully updated Zoom meeting {zoom_meeting.meeting_id}, but failed to fetch updated details. "
                        f"Error: {details_result.get('message', 'Unknown error')}"
                    )
                    # Update with form data as a fallback
                    zoom_meeting.topic = new_topic
                    zoom_meeting.start_time = new_start_time
                    zoom_meeting.duration = new_duration
                    zoom_meeting.save()
                    scheduled_interview.interview_date = new_start_time.date()
                    scheduled_interview.interview_time = new_start_time.time()
                    scheduled_interview.save()
                    messages.success(
                        request,
                        f"Meeting for {application.name} rescheduled. (Note: Could not refresh all details from Zoom.)",
                    )

                return redirect("candidate_interview_view", slug=job.slug)
            else:
                messages.error(
                    request,
                    f"Failed to update Zoom meeting: {zoom_update_result['message']}",
                )
                # Re-render form with error
                return render(
                    request,
                    "recruitment/schedule_meeting_form.html",
                    {
                        "form": form,
                        "job": job,
                        "application": application,
                        "scheduled_interview": scheduled_interview,
                        "initial_topic": new_topic,
                        "initial_start_time": new_start_time.strftime("%Y-%m-%dT%H:%M")
                        if new_start_time
                        else "",
                        "initial_duration": new_duration,
                        "action_url": reverse(
                            "reschedule_candidate_meeting",
                            kwargs={
                                "job_slug": job_slug,
                                "candidate_pk": candidate_pk,
                                "interview_pk": interview_pk,
                            },
                        ),
                        "has_future_meeting": has_other_future_meetings,
                    },
                )
        else:
            # Form validation errors
            return render(
                request,
                "recruitment/schedule_meeting_form.html",
                {
                    "form": form,
                    "job": job,
                    "application": application,
                    "scheduled_interview": scheduled_interview,
                    "initial_topic": request.POST.get("topic", new_topic),
                    "initial_start_time": request.POST.get(
                        "start_time",
                        new_start_time.strftime("%Y-%m-%dT%H:%M")
                        if new_start_time
                        else "",
                    ),
                    "initial_duration": request.POST.get("duration", new_duration),
                    "action_url": reverse(
                        "reschedule_candidate_meeting",
                        kwargs={
                            "job_slug": job_slug,
                            "candidate_pk": candidate_pk,
                            "interview_pk": interview_pk,
                        },
                    ),
                    "has_future_meeting": has_other_future_meetings,
                },
            )
    else:  # GET request
        # Pre-populate form with existing meeting details
        initial_data = {
            "topic": zoom_meeting.topic,
            "start_time": zoom_meeting.start_time.strftime("%Y-%m-%dT%H:%M"),
            "duration": zoom_meeting.duration,
        }
        form = ZoomMeetingForm(initial=initial_data)
        return render(
            request,
            "recruitment/schedule_meeting_form.html",
            {
                "form": form,
                "job": job,
                "application": application,
                "scheduled_interview": scheduled_interview,  # Pass to template for title/differentiation
                "action_url": reverse(
                    "reschedule_candidate_meeting",
                    kwargs={
                        "job_slug": job_slug,
                        "candidate_pk": candidate_pk,
                        "interview_pk": interview_pk,
                    },
                ),
                "has_future_meeting": has_other_future_meetings,  # Pass status for template
            },
        )


def schedule_meeting_for_candidate(request, slug, candidate_pk):
    """
    Handles GET to display a simple form for scheduling a meeting for a candidate.
    Handles POST to process the form, create a meeting, and redirect back.
    """
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_pk, job=job)

    if request.method == "POST":
        form = ZoomMeetingForm(request.POST)
        if form.is_valid():
            topic_val = form.cleaned_data.get("topic")
            start_time_val = form.cleaned_data.get("start_time")
            duration_val = form.cleaned_data.get("duration")

            # Use a default topic if not provided
            if not topic_val:
                topic_val = f"Interview: {job.title} with {candidate.name}"

            # Ensure start_time is in the future
            if start_time_val <= timezone.now():
                messages.error(request, "Start time must be in the future.")
                # Re-render form with error and initial data
                return redirect("candidate_interview_view", slug=job.slug)
                # return render(request, "recruitment/schedule_meeting_form.html", {
                #     'form': form,
                #     'job': job,
                #     'candidate': candidate,
                #     'initial_topic': topic_val,
                #     'initial_start_time': start_time_val.strftime('%Y-%m-%dT%H:%M') if start_time_val else '',
                #     'initial_duration': duration_val
                # })

            # Create Zoom meeting using utility function
            # The create_zoom_meeting expects start_time as a datetime object
            # and handles its own conversion to UTC for the API call.
            zoom_creation_result = create_zoom_meeting(
                topic=topic_val,
                start_time=start_time_val,  # Pass the datetime object
                duration=duration_val,
            )

            if zoom_creation_result["status"] == "success":
                zoom_details = zoom_creation_result["meeting_details"]
                zoom_meeting_instance = ZoomMeetingDetails.objects.create(
                    topic=topic_val,
                    start_time=start_time_val,  # Store the original datetime
                    duration=duration_val,
                    meeting_id=zoom_details["meeting_id"],
                    details_url=zoom_details["join_url"],
                    password=zoom_details.get("password"),  # password might be None
                    status=zoom_creation_result["zoom_gateway_response"].get(
                        "status", "waiting"
                    ),
                    zoom_gateway_response=zoom_creation_result["zoom_gateway_response"],
                    location_type='Remote',

                )
                # Create a ScheduledInterview record
                ScheduledInterview.objects.create(
                    application=candidate,
                    job=job,
                    interview_location=zoom_meeting_instance,
                    interview_date=start_time_val.date(),
                    interview_time=start_time_val.time(),
                    status="scheduled",
                )
                messages.success(request, f"Meeting scheduled with {candidate.name}.")
                return redirect("candidate_interview_view", slug=job.slug)
            else:
                messages.error(
                    request,
                    f"Failed to create Zoom meeting: {zoom_creation_result['message']}",
                )
                # Re-render form with error
                return render(
                    request,
                    "recruitment/schedule_meeting_form.html",
                    {
                        "form": form,
                        "job": job,
                        "candidate": candidate,
                        "initial_topic": topic_val,
                        "initial_start_time": start_time_val.strftime("%Y-%m-%dT%H:%M")
                        if start_time_val
                        else "",
                        "initial_duration": duration_val,
                    },
                )
        else:
            # Form validation errors
            return render(
                request,
                "meetings/schedule_meeting_form.html",
                {
                    "form": form,
                    "job": job,
                    "candidate": candidate,
                    "initial_topic": request.POST.get(
                        "topic", f"Interview: {job.title} with {candidate.name}"
                    ),
                    "initial_start_time": request.POST.get("start_time", ""),
                    "initial_duration": request.POST.get("duration", 60),
                },
            )
    else:  # GET request
        initial_data = {
            "topic": f"Interview: {job.title} with {candidate.name}",
            "start_time": (timezone.now() + timedelta(hours=1)).strftime(
                "%Y-%m-%dT%H:%M"
            ),  # Default to 1 hour from now
            "duration": 60,  # Default duration
        }
        form = ZoomMeetingForm(initial=initial_data)
        return render(
            request,
            "meetings/schedule_meeting_form.html",
            {"form": form, "job": job, "candidate": candidate},
        )


from django.core.exceptions import ObjectDoesNotExist


def user_profile_image_update(request, pk):
    user = get_object_or_404(User, pk=pk)

    if request.method == "POST":
        profile_form = ProfileImageUploadForm(
            request.POST, request.FILES, instance=user
        )
        if profile_form.is_valid():
            profile_form.save()
            messages.success(request, "Image uploaded successfully")
            return redirect("user_detail", pk=user.pk)
        else:
            messages.error(
                request,
                "An error occurred while uploading image. Please check errors below.",
            )
    else:
        profile_form = ProfileImageUploadForm(instance=user)

    context = {
        "profile_form": profile_form,
        "user": user,
    }
    return render(request, "user/profile.html", context)


def user_detail(request, pk):
    user = get_object_or_404(User, pk=pk)

    profile_form = ProfileImageUploadForm(instance=user)

    if request.method == "POST":
        first_name = request.POST.get("first_name")
        last_name = request.POST.get("last_name")
        if first_name:
            user.first_name = first_name
        if last_name:
            user.last_name = last_name
        user.save()
    context = {"user": user, "profile_form": profile_form,"password_reset_form":PasswordResetForm()}
    if request.user.user_type != "staff":
        return render(request, "user/portal_profile.html", context)
    return render(request, "user/profile.html", context)


def easy_logs(request):
    """
    Function-based view to display Django Easy Audit logs with tab switching and pagination.
    """
    logs_per_page = 20

    active_tab = request.GET.get("tab", "crud")

    if active_tab == "login":
        queryset = LoginEvent.objects.order_by("-datetime")
        tab_title = _("User Authentication")
    elif active_tab == "request":
        queryset = RequestEvent.objects.order_by("-datetime")
        tab_title = _("HTTP Requests")
    else:
        queryset = CRUDEvent.objects.order_by("-datetime")
        tab_title = _("Model Changes (CRUD)")
        active_tab = "crud"

    paginator = Paginator(queryset, logs_per_page)
    page = request.GET.get("page")

    try:
        logs_page = paginator.page(page)
    except PageNotAnInteger:
        logs_page = paginator.page(1)
    except EmptyPage:
        logs_page = paginator.page(paginator.num_pages)

    context = {
        "logs": logs_page,
        "total_count": queryset.count(),
        "active_tab": active_tab,
        "tab_title": tab_title,
    }

    return render(request, "includes/easy_logs.html", context)


from allauth.account.views import SignupView
from django.contrib.auth.decorators import user_passes_test


def is_superuser_check(user):
    return user.is_superuser


@staff_user_required
def create_staff_user(request):
    if request.method == "POST":
        form = StaffUserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(
                request,
                f"Staff user {form.cleaned_data['first_name']} {form.cleaned_data['last_name']} "
                f"({form.cleaned_data['email']}) created successfully!",
            )
            return redirect("admin_settings")
    else:
        form = StaffUserCreationForm()
    return render(request, "user/create_staff.html", {"form": form})


@staff_user_required
def admin_settings(request):
    staffs = User.objects.filter(user_type="staff",is_superuser=False)
    form = ToggleAccountForm()
    context = {"staffs": staffs, "form": form}
    return render(request, "user/admin_settings.html", context)

@staff_user_required
def staff_assignment_view(request, slug):
    """
    View to assign staff to a job posting
    """
    job = get_object_or_404(JobPosting, slug=slug)
    staff_users = User.objects.filter(user_type="staff", is_superuser=False)
    applications = job.applications.all()

    if request.method == "POST":
        form = StaffAssignmentForm(request.POST, instance=job) 
       
        if form.is_valid():
            assignment = form.save()
            messages.success(request, f"Staff assigned to job '{job.title}' successfully!")
            return redirect("job_detail", slug=job.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = StaffAssignmentForm(instance=job)
    print(staff_users)
    context = {
        "job": job,
        "applications": applications,
        "staff_users": staff_users,
        "form": form,
    }
    return render(request, "recruitment/staff_assignment_view.html", context)


from django.contrib.auth.forms import SetPasswordForm


@staff_user_required
def set_staff_password(request, pk):
    user = get_object_or_404(User, pk=pk)
    print(request.POST)
    if request.method == "POST":
        form = SetPasswordForm(user, data=request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, f"Password successfully changed")
            return redirect("admin_settings")
        else:
            form = SetPasswordForm(user=user)
            messages.error(request, f"Password does not match please try again.")
            return redirect("admin_settings")

    else:
        form = SetPasswordForm(user=user)
    return render(
        request, "user/staff_password_create.html", {"form": form, "user": user}
    )


@staff_user_required
def account_toggle_status(request, pk):
    user = get_object_or_404(User, pk=pk)
    if request.method == "POST":
        print(user.is_active)
        form = ToggleAccountForm(request.POST)
        if form.is_valid():
            if user.is_active:
                user.is_active = False
                user.save()
                messages.success(
                    request, f"Staff with email: {user.email} deactivated successfully"
                )
                return redirect("admin_settings")
            else:
                user.is_active = True
                user.save()
                messages.success(
                    request, f"Staff with email: {user.email} activated successfully"
                )
                return redirect("admin_settings")
        else:
            messages.error(f"Please correct the error below")


# @login_required
# def user_detail(requests,pk):
#         user=get_object_or_404(User,pk=pk)
#         return render(requests,'user/profile.html')


@csrf_exempt
def zoom_webhook_view(request):
    api_key = request.headers.get("X-Zoom-API-KEY")
    if api_key != settings.ZOOM_WEBHOOK_API_KEY:
        return HttpResponse(status=405)

    if request.method == "POST":
        try:
            payload = json.loads(request.body)
            async_task("recruitment.tasks.handle_zoom_webhook_event", payload)
            return HttpResponse(status=200)
        except Exception:
            return HttpResponse(status=400)
    return HttpResponse(status=405)


# Meeting Comments Views
@staff_user_required
def add_meeting_comment(request, slug):
    """Add a comment to a meeting"""
    # from .forms import MeetingCommentForm

    meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)

    if request.method == "POST":
        form = InterviewNoteForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.meeting = meeting
            comment.author = request.user
            comment.save()
            messages.success(request, "Comment added successfully!")

            # HTMX response - return just the comment section
            if "HX-Request" in request.headers:
                return render(
                    request,
                    "includes/comment_list.html",
                    {
                        "comments": meeting.comments.all().order_by("-created_at"),
                        "meeting": meeting,
                    },
                )

            return redirect("meeting_details", slug=slug)
    else:
        form = InterviewNoteForm()

    context = {
        "form": form,
        "meeting": meeting,
    }

    # HTMX response - return the comment form
    if "HX-Request" in request.headers:
        return render(request, "includes/comment_form.html", context)

    return redirect("meeting_details", slug=slug)


@staff_user_required
def edit_meeting_comment(request, slug, comment_id):
    """Edit a meeting comment"""
    meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
    comment = get_object_or_404(InterviewNote, id=comment_id, meeting=meeting)

    # Check if user is author
    if comment.author != request.user and not request.user.is_staff:
        messages.error(request, "You can only edit your own comments.")
        return redirect("meeting_details", slug=slug)

    if request.method == "POST":
        form = InterviewNoteForm(request.POST, instance=comment)
        if form.is_valid():
            comment = form.save()
            messages.success(request, "Comment updated successfully!")

            # HTMX response - return just comment section
            if "HX-Request" in request.headers:
                return render(
                    request,
                    "includes/comment_list.html",
                    {
                        "comments": meeting.comments.all().order_by("-created_at"),
                        "meeting": meeting,
                    },
                )

            return redirect("meeting_details", slug=slug)
    else:
        form = InterviewNoteForm(instance=comment)

    context = {"form": form, "meeting": meeting, "comment": comment}
    return render(request, "includes/edit_comment_form.html", context)


@staff_user_required
def delete_meeting_comment(request, slug, comment_id):
    """Delete a meeting comment"""
    meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
    comment = get_object_or_404(InterviewNote, id=comment_id, meeting=meeting)

    # Check if user is the author
    if comment.author != request.user and not request.user.is_staff:
        messages.error(request, "You can only delete your own comments.")
        return redirect("meeting_details", slug=slug)

    if request.method == "POST":
        comment.delete()
        messages.success(request, "Comment deleted successfully!")

        # HTMX response - return just the comment section
        if "HX-Request" in request.headers:
            return render(
                request,
                "includes/comment_list.html",
                {
                    "comments": meeting.comments.all().order_by("-created_at"),
                    "meeting": meeting,
                },
            )

        return redirect("meeting_details", slug=slug)

    # HTMX response - return the delete confirmation modal
    if "HX-Request" in request.headers:
        return render(
            request,
            "includes/delete_comment_form.html",
            {
                "meeting": meeting,
                "comment": comment,
                "delete_url": reverse(
                    "delete_meeting_comment",
                    kwargs={"slug": slug, "comment_id": comment_id},
                ),
            },
        )

    return redirect("meeting_details", slug=slug)


@staff_user_required
def set_meeting_candidate(request, slug):
    meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
    if request.method == "POST" and "HX-Request" not in request.headers:
        form = InterviewForm(request.POST)
        if form.is_valid():
            candidate = form.save(commit=False)
            candidate.zoom_meeting = meeting
            candidate.interview_date = meeting.start_time.date()
            candidate.interview_time = meeting.start_time.time()
            candidate.save()
            messages.success(request, "Candidate added successfully!")
            return redirect("list_meetings")
    job = request.GET.get("job")
    form = InterviewForm()

    if job:
        form.fields["candidate"].queryset = Application.objects.filter(job=job)

    else:
        form.fields["candidate"].queryset = Application.objects.none()
    form.fields["job"].widget.attrs.update(
        {
            "hx-get": reverse("set_meeting_candidate", kwargs={"slug": slug}),
            "hx-target": "#div_id_candidate",
            "hx-select": "#div_id_candidate",
            "hx-swap": "outerHTML",
        }
    )
    context = {"form": form, "meeting": meeting}
    return render(request, "meetings/set_candidate_form.html", context)


# Hiring Agency CRUD Views
@staff_user_required
def agency_list(request):
    """List all hiring agencies with search and pagination"""
    search_query = request.GET.get("search", "")
    agencies = HiringAgency.objects.all()

    if search_query:
        agencies = agencies.filter(
            Q(name__icontains=search_query)
            | Q(contact_person__icontains=search_query)
            | Q(email__icontains=search_query)
            | Q(country__icontains=search_query)
        )

    # Order by most recently created
    agencies = agencies.order_by("-created_at")

    # Pagination
    paginator = Paginator(agencies, 10)  # Show 10 agencies per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    context = {
        "page_obj": page_obj,
        "search_query": search_query,
        "total_agencies": agencies.count(),
    }
    return render(request, "recruitment/agency_list.html", context)


@staff_user_required
def agency_create(request):
    """Create a new hiring agency"""
    if request.method == "POST":
        form = HiringAgencyForm(request.POST)
        if form.is_valid():
            agency = form.save()
            messages.success(request, f'Agency "{agency.name}" created successfully!')
            return redirect("agency_detail", slug=agency.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = HiringAgencyForm()

    context = {
        "form": form,
        "title": "Create New Agency",
        "button_text": "Create Agency",
    }
    return render(request, "recruitment/agency_form.html", context)


@staff_user_required
def agency_detail(request, slug):
    """View details of a specific hiring agency"""
    agency = get_object_or_404(HiringAgency, slug=slug)

    # Get candidates associated with this agency
    candidates = Application.objects.filter(hiring_agency=agency).order_by(
        "-created_at"
    )

    # Statistics
    total_candidates = candidates.count()
    active_candidates = candidates.filter(
        stage__in=["Applied", "Screening", "Exam", "Interview", "Offer"]
    ).count()
    hired_candidates = candidates.filter(stage="Hired").count()
    rejected_candidates = candidates.filter(stage="Rejected").count()

    context = {
        "agency": agency,
        "candidates": candidates[:10],  # Show recent 10 candidates
        "total_candidates": total_candidates,
        "active_candidates": active_candidates,
        "hired_candidates": hired_candidates,
        "rejected_candidates": rejected_candidates,
        "generated_password": agency.generated_password
        if agency.generated_password
        else None,
    }
    return render(request, "recruitment/agency_detail.html", context)


@staff_user_required
def agency_update(request, slug):
    """Update an existing hiring agency"""
    agency = get_object_or_404(HiringAgency, slug=slug)

    if request.method == "POST":
        form = HiringAgencyForm(request.POST, instance=agency)
        if form.is_valid():
            agency = form.save()
            messages.success(request, f'Agency "{agency.name}" updated successfully!')
            return redirect("agency_detail", slug=agency.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = HiringAgencyForm(instance=agency)

    context = {
        "form": form,
        "agency": agency,
        "title": f"Edit Agency: {agency.name}",
        "button_text": "Update Agency",
    }
    return render(request, "recruitment/agency_form.html", context)


@staff_user_required
def agency_delete(request, slug):
    """Delete a hiring agency"""
    agency = get_object_or_404(HiringAgency, slug=slug)

    if request.method == "POST":
        agency_name = agency.name
        agency.delete()
        messages.success(request, f'Agency "{agency_name}" deleted successfully!')
        return redirect("agency_list")

    context = {
        "agency": agency,
        "title": "Delete Agency",
        "message": f'Are you sure you want to delete the agency "{agency.name}"?',
        "cancel_url": reverse("agency_detail", kwargs={"slug": agency.slug}),
    }
    return render(request, "recruitment/agency_confirm_delete.html", context)


# Notification Views
# @staff_user_required
# def notification_list(request):
#     """List all notifications for the current user"""
#     # Get filter parameters
#     status_filter = request.GET.get('status', '')
#     type_filter = request.GET.get('type', '')

#     # Base queryset
#     notifications = Notification.objects.filter(recipient=request.user).order_by('-created_at')

#     # Apply filters
#     if status_filter:
#         if status_filter == 'unread':
#             notifications = notifications.filter(status=Notification.Status.PENDING)
#         elif status_filter == 'read':
#             notifications = notifications.filter(status=Notification.Status.READ)
#         elif status_filter == 'sent':
#             notifications = notifications.filter(status=Notification.Status.SENT)

#     if type_filter:
#         if type_filter == 'in_app':
#             notifications = notifications.filter(notification_type=Notification.NotificationType.IN_APP)
#         elif type_filter == 'email':
#             notifications = notifications.filter(notification_type=Notification.NotificationType.EMAIL)

#     # Pagination
#     paginator = Paginator(notifications, 20)  # Show 20 notifications per page
#     page_number = request.GET.get('page')
#     page_obj = paginator.get_page(page_number)

#     # Statistics
#     total_notifications = notifications.count()
#     unread_notifications = notifications.filter(status=Notification.Status.PENDING).count()
#     email_notifications = notifications.filter(notification_type=Notification.NotificationType.EMAIL).count()

#     context = {
#         'page_obj': page_obj,
#         'total_notifications': total_notifications,
#         'unread_notifications': unread_notifications,
#         'email_notifications': email_notifications,
#         'status_filter': status_filter,
#         'type_filter': type_filter,
#     }
#     return render(request, 'recruitment/notification_list.html', context)


# @staff_user_required
# def notification_detail(request, notification_id):
#     """View details of a specific notification"""
#     notification = get_object_or_404(Notification, id=notification_id, recipient=request.user)

#     # Mark as read if it was pending
#     if notification.status == Notification.Status.PENDING:
#         notification.status = Notification.Status.READ
#         notification.save(update_fields=['status'])

#     context = {
#         'notification': notification,
#     }
#     return render(request, 'recruitment/notification_detail.html', context)


# @staff_user_required
# def notification_mark_read(request, notification_id):
#     """Mark a notification as read"""
#     notification = get_object_or_404(Notification, id=notification_id, recipient=request.user)

#     if notification.status == Notification.Status.PENDING:
#         notification.status = Notification.Status.READ
#         notification.save(update_fields=['status'])

#     if 'HX-Request' in request.headers:
#         return HttpResponse(status=200)  # HTMX success response

#     return redirect('notification_list')


# @staff_user_required
# def notification_mark_unread(request, notification_id):
#     """Mark a notification as unread"""
#     notification = get_object_or_404(Notification, id=notification_id, recipient=request.user)

#     if notification.status == Notification.Status.READ:
#         notification.status = Notification.Status.PENDING
#         notification.save(update_fields=['status'])

#     if 'HX-Request' in request.headers:
#         return HttpResponse(status=200)  # HTMX success response

#     return redirect('notification_list')


# @staff_user_required
# def notification_delete(request, notification_id):
#     """Delete a notification"""
#     notification = get_object_or_404(Notification, id=notification_id, recipient=request.user)

#     if request.method == 'POST':
#         notification.delete()
#         messages.success(request, 'Notification deleted successfully!')
#         return redirect('notification_list')

#     # For GET requests, show confirmation page
#     context = {
#         'notification': notification,
#         'title': 'Delete Notification',
#         'message': f'Are you sure you want to delete this notification?',
#         'cancel_url': reverse('notification_detail', kwargs={'notification_id': notification.id}),
#     }
#     return render(request, 'recruitment/notification_confirm_delete.html', context)


# @staff_user_required
# def notification_mark_all_read(request):
#     """Mark all notifications as read for the current user"""
#     if request.method == 'POST':
#         Notification.objects.filter(
#             recipient=request.user,
#             status=Notification.Status.PENDING
#         ).update(status=Notification.Status.READ)

#         messages.success(request, 'All notifications marked as read!')
#         return redirect('notification_list')

#     # For GET requests, show confirmation page
#     unread_count = Notification.objects.filter(
#         recipient=request.user,
#         status=Notification.Status.PENDING
#     ).count()

#     context = {
#         'unread_count': unread_count,
#         'title': 'Mark All as Read',
#         'message': f'Are you sure you want to mark all {unread_count} notifications as read?',
#         'cancel_url': reverse('notification_list'),
#     }
#     return render(request, 'recruitment/notification_confirm_all_read.html', context)


# @staff_user_required
# def api_notification_count(request):
#     """API endpoint to get unread notification count and recent notifications"""
#     # Get unread notifications
#     unread_notifications = Notification.objects.filter(
#         recipient=request.user,
#         status=Notification.Status.PENDING
#     ).order_by('-created_at')

#     # Get recent notifications (last 5)
#     recent_notifications = Notification.objects.filter(
#         recipient=request.user
#     ).order_by('-created_at')[:5]

#     # Prepare recent notifications data
#     recent_data = []
#     for notification in recent_notifications:
#         time_ago = ''
#         if notification.created_at:
#             from datetime import datetime, timezone
#             now = timezone.now()
#             diff = now - notification.created_at

#             if diff.days > 0:
#                 time_ago = f'{diff.days}d ago'
#             elif diff.seconds > 3600:
#                 hours = diff.seconds // 3600
#                 time_ago = f'{hours}h ago'
#             elif diff.seconds > 60:
#                 minutes = diff.seconds // 60
#                 time_ago = f'{minutes}m ago'
#             else:
#                 time_ago = 'Just now'

#         recent_data.append({
#             'id': notification.id,
#             'message': notification.message[:100] + ('...' if len(notification.message) > 100 else ''),
#             'type': notification.get_notification_type_display(),
#             'status': notification.get_status_display(),
#             'time_ago': time_ago,
#             'url': reverse('notification_detail', kwargs={'notification_id': notification.id})
#         })

#     return JsonResponse({
#         'count': unread_notifications.count(),
#         'recent_notifications': recent_data
#     })


# @staff_user_required
# def notification_stream(request):
#     """SSE endpoint for real-time notifications"""
#     from django.http import StreamingHttpResponse
#     import json
#     import time
#     from .signals import SSE_NOTIFICATION_CACHE

#     def event_stream():
#         """Generator function for SSE events"""
#         user_id = request.user.id
#         last_notification_id = 0

#         # Get initial last notification ID
#         last_notification = Notification.objects.filter(
#             recipient=request.user
#         ).order_by('-id').first()
#         if last_notification:
#             last_notification_id = last_notification.id

#         # Send any cached notifications first
#         cached_notifications = SSE_NOTIFICATION_CACHE.get(user_id, [])
#         for cached_notification in cached_notifications:
#             if cached_notification['id'] > last_notification_id:
#                 yield f"event: new_notification\n"
#                 yield f"data: {json.dumps(cached_notification)}\n\n"
#                 last_notification_id = cached_notification['id']

#         while True:
#             try:
#                 # Check for new notifications from cache first
#                 cached_notifications = SSE_NOTIFICATION_CACHE.get(user_id, [])
#                 new_cached = [n for n in cached_notifications if n['id'] > last_notification_id]

#                 for notification_data in new_cached:
#                     yield f"event: new_notification\n"
#                     yield f"data: {json.dumps(notification_data)}\n\n"
#                     last_notification_id = notification_data['id']

#                 # Also check database for any missed notifications
#                 new_notifications = Notification.objects.filter(
#                     recipient=request.user,
#                     id__gt=last_notification_id
#                 ).order_by('id')

#                 if new_notifications.exists():
#                     for notification in new_notifications:
#                         # Prepare notification data
#                         time_ago = ''
#                         if notification.created_at:
#                             now = timezone.now()
#                             diff = now - notification.created_at

#                             if diff.days > 0:
#                                 time_ago = f'{diff.days}d ago'
#                             elif diff.seconds > 3600:
#                                 hours = diff.seconds // 3600
#                                 time_ago = f'{hours}h ago'
#                             elif diff.seconds > 60:
#                                 minutes = diff.seconds // 60
#                                 time_ago = f'{minutes}m ago'
#                             else:
#                                 time_ago = 'Just now'

#                         notification_data = {
#                             'id': notification.id,
#                             'message': notification.message[:100] + ('...' if len(notification.message) > 100 else ''),
#                             'type': notification.get_notification_type_display(),
#                             'status': notification.get_status_display(),
#                             'time_ago': time_ago,
#                             'url': reverse('notification_detail', kwargs={'notification_id': notification.id})
#                         }

#                         # Send SSE event
#                         yield f"event: new_notification\n"
#                         yield f"data: {json.dumps(notification_data)}\n\n"

#                         last_notification_id = notification.id

#                     # Update count after sending new notifications
#                     unread_count = Notification.objects.filter(
#                         recipient=request.user,
#                         status=Notification.Status.PENDING
#                     ).count()

#                     count_data = {'count': unread_count}
#                     yield f"event: count_update\n"
#                     yield f"data: {json.dumps(count_data)}\n\n"

#                 # Send heartbeat every 30 seconds
#                 yield f"event: heartbeat\n"
#                 yield f"data: {json.dumps({'timestamp': int(time.time())})}\n\n"

#                 # Wait before next check
#                 time.sleep(5)  # Check every 5 seconds

#             except Exception as e:
#                 # Send error event and continue
#                 error_data = {'error': str(e)}
#                 yield f"event: error\n"
#                 yield f"data: {json.dumps(error_data)}\n\n"
#                 time.sleep(10)  # Wait longer on error

#     response = StreamingHttpResponse(
#         event_stream(),
#         content_type='text/event-stream'
#     )

#     # Set SSE headers
#     response['Cache-Control'] = 'no-cache'
#     response['X-Accel-Buffering'] = 'no'  # Disable buffering for nginx
#     response['Connection'] = 'keep-alive'

# context = {
#     'agency': agency,
#     'page_obj': page_obj,
#     'stage_filter': stage_filter,
#     'total_candidates': candidates.count(),
# }
# return render(request, 'recruitment/agency_candidates.html', context)


@staff_user_required
def agency_candidates(request, slug):
    """View all candidates from a specific agency"""
    agency = get_object_or_404(HiringAgency, slug=slug)
    candidates = Application.objects.filter(hiring_agency=agency).order_by(
        "-created_at"
    )

    # Filter by stage if provided
    stage_filter = request.GET.get("stage")
    if stage_filter:
        candidates = candidates.filter(stage=stage_filter)

    # Get total candidates before pagination for accurate count
    total_candidates = candidates.count()

    # Pagination
    paginator = Paginator(candidates, 20)  # Show 20 candidates per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    context = {
        "agency": agency,
        "page_obj": page_obj,
        "stage_filter": stage_filter,
        "total_candidates": total_candidates,
    }
    return render(request, "recruitment/agency_candidates.html", context)


# Agency Portal Management Views
@staff_user_required
def agency_assignment_list(request):
    """List all agency job assignments"""
    search_query = request.GET.get("q", "")
    status_filter = request.GET.get("status", "")

    assignments = AgencyJobAssignment.objects.select_related("agency", "job").order_by(
        "-created_at"
    )

    if search_query:
        assignments = assignments.filter(
            Q(agency__name__icontains=search_query)
            | Q(job__title__icontains=search_query)
        )

    if status_filter:
        assignments = assignments.filter(status=status_filter)

    # Pagination
    paginator = Paginator(assignments, 15)  # Show 15 assignments per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    context = {
        "page_obj": page_obj,
        "search_query": search_query,
        "status_filter": status_filter,
        "total_assignments": assignments.count(),
    }
    return render(request, "recruitment/agency_assignment_list.html", context)


@staff_user_required
def agency_assignment_create(request, slug=None):
    """Create a new agency job assignment"""
    agency = HiringAgency.objects.get(slug=slug) if slug else None

    if request.method == "POST":
        form = AgencyJobAssignmentForm(request.POST)
        # if agency:
        #     form.instance.agency = agency
        if form.is_valid():
            assignment = form.save()
            messages.success(
                request,
                f"Assignment created for {assignment.agency.name} - {assignment.job.title}!",
            )
            return redirect("agency_assignment_detail", slug=assignment.slug)
        else:
            messages.error(
                request, f"Please correct the errors below.{form.errors.as_text()}"
            )
            print(form.errors.as_json())
    else:
        form = AgencyJobAssignmentForm()
        try:
            # from django.forms import HiddenInput
            form.initial["agency"] = agency
            # form.fields['agency'].widget = HiddenInput()
        except HiringAgency.DoesNotExist:
            pass

    context = {
        "form": form,
        "title": "Create New Assignment",
        "button_text": "Create Assignment",
    }
    return render(request, "recruitment/agency_assignment_form.html", context)


@staff_user_required
def agency_assignment_detail(request, slug):
    """View details of a specific agency assignment"""
    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), slug=slug
    )

    # Get candidates submitted by this agency for this job
    candidates = Application.objects.filter(
        hiring_agency=assignment.agency, job=assignment.job
    ).order_by("-created_at")

    # Get access link if exists
    access_link = getattr(assignment, "access_link", None)

    # Get messages for this assignment

    total_candidates = candidates.count()
    max_candidates = assignment.max_candidates
    circumference = 326.73  # 2 * π * r where r=52

    if max_candidates > 0:
        progress_percentage = total_candidates / max_candidates
        stroke_dashoffset = circumference - (circumference * progress_percentage)
    else:
        stroke_dashoffset = circumference

    context = {
        "assignment": assignment,
        "candidates": candidates,
        "access_link": access_link,
        "total_candidates": candidates.count(),
        "stroke_dashoffset": stroke_dashoffset,
    }
    return render(request, "recruitment/agency_assignment_detail.html", context)


@staff_user_required
def agency_assignment_update(request, slug):
    """Update an existing agency assignment"""
    assignment = get_object_or_404(AgencyJobAssignment, slug=slug)

    if request.method == "POST":
        form = AgencyJobAssignmentForm(request.POST, instance=assignment)
        if form.is_valid():
            assignment = form.save()
            messages.success(request, f"Assignment updated successfully!")
            return redirect("agency_assignment_detail", slug=assignment.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = AgencyJobAssignmentForm(instance=assignment)

    context = {
        "form": form,
        "assignment": assignment,
        "title": f"Edit Assignment: {assignment.agency.name} - {assignment.job.title}",
        "button_text": "Update Assignment",
    }
    return render(request, "recruitment/agency_assignment_form.html", context)


@staff_user_required
def agency_access_link_create(request):
    """Create access link for agency assignment"""
    if request.method == "POST":
        form = AgencyAccessLinkForm(request.POST)
        if form.is_valid():
            access_link = form.save()
            messages.success(
                request,
                f"Access link created for {access_link.assignment.agency.name}!",
            )
            return redirect(
                "agency_assignment_detail", slug=access_link.assignment.slug
            )
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = AgencyAccessLinkForm()

    context = {
        "form": form,
        "title": "Create Access Link",
        "button_text": "Create Link",
    }
    return render(request, "recruitment/agency_access_link_form.html", context)


@staff_user_required
def agency_access_link_detail(request, slug):
    """View details of an access link"""
    access_link = get_object_or_404(
        AgencyAccessLink.objects.select_related(
            "assignment__agency", "assignment__job"
        ),
        slug=slug,
    )

    context = {
        "access_link": access_link,
    }
    return render(request, "recruitment/agency_access_link_detail.html", context)


@staff_user_required
def agency_assignment_extend_deadline(request, slug):
    """Extend deadline for an agency assignment"""
    assignment = get_object_or_404(AgencyJobAssignment, slug=slug)

    if request.method == "POST":
        new_deadline = request.POST.get("new_deadline")
        if new_deadline:
            try:
                from datetime import datetime

                new_deadline_dt = datetime.fromisoformat(
                    new_deadline.replace("Z", "+00:00")
                )
                # Ensure the new deadline is timezone-aware
                if timezone.is_naive(new_deadline_dt):
                    new_deadline_dt = timezone.make_aware(new_deadline_dt)

                if assignment.extend_deadline(new_deadline_dt):
                    messages.success(
                        request,
                        f"Deadline extended to {new_deadline_dt.strftime('%Y-%m-%d %H:%M')}!",
                    )
                else:
                    messages.error(
                        request, "New deadline must be later than current deadline."
                    )
            except ValueError:
                messages.error(request, "Invalid date format.")
        else:
            messages.error(request, "Please provide a new deadline.")

    return redirect("agency_assignment_detail", slug=assignment.slug)



@require_POST
def portal_password_reset(request,pk):
    user = get_object_or_404(User, pk=pk)
    if request.method == 'POST':
        form = PasswordResetForm(request.POST)
        if form.is_valid():
            # Verify old password
            old_password = form.cleaned_data['old_password']
            if not user.check_password(old_password):
                messages.error(request, 'Old password is incorrect.')
                return redirect('user_detail', pk=user.pk)

            # Set new password
            user.set_password(form.cleaned_data['new_password1'])
            user.save()
            messages.success(request, 'Password reset successfully.')
            return redirect('user_detail',pk=user.pk)
        else:
            for field, errors in form.errors.items():
                for error in errors:
                    messages.error(request, f"{field}: {error}")

# Agency Portal Views (for external agencies)
def agency_portal_login(request):
    """Agency login page"""
    # if request.session.get("agency_assignment_id"):
    #     return redirect("agency_portal_dashboard")
    if request.method == "POST":
        form = AgencyLoginForm(request.POST)

        if form.is_valid():
            # Check if validated_access_link attribute exists

            # if hasattr(form, "validated_access_link"):
            #     access_link = form.validated_access_link
            # access_link.record_access()

            # Store assignment in session
            # request.session["agency_assignment_id"] = access_link.assignment.id
            # request.session["agency_name"] = access_link.assignment.agency.name

            messages.success(request, f"Welcome, {access_link.assignment.agency.name}!")
            return redirect("agency_portal_dashboard")
        else:
            messages.error(request, "Invalid token or password.")
    else:
        form = AgencyLoginForm()

    context = {
        "form": form,
    }
    return render(request, "recruitment/agency_portal_login.html", context)


def portal_login(request):
    """Unified portal login for agency and candidate"""
    if request.user.is_authenticated:
        if request.user.user_type == "agency":
            return redirect("agency_portal_dashboard")
        if request.user.user_type == "candidate":
            print(request.user)
            return redirect("candidate_portal_dashboard")

    if request.method == "POST":
        form = PortalLoginForm(request.POST)

        if form.is_valid():
            email = form.cleaned_data["email"]
            password = form.cleaned_data["password"]
            user_type = form.cleaned_data["user_type"]

            # Authenticate user
            user = authenticate(request, username=email, password=password)
            if user is not None:
                # Check if user type matches
                if hasattr(user, "user_type") and user.user_type == user_type:
                    login(request, user)
                    return redirect("agency_portal_dashboard")

                    # if user_type == "agency":
                    #     # Check if user has agency profile
                    #     if hasattr(user, "agency_profile") and user.agency_profile:
                    #         messages.success(
                    #             request, f"Welcome, {user.agency_profile.name}!"
                    #         )
                    #         return redirect("agency_portal_dashboard")
                    #     else:
                    #         messages.error(
                    #             request, "No agency profile found for this user."
                    #         )
                    #         logout(request)

                    # elif user_type == "candidate":
                    #     # Check if user has candidate profile
                    #     if (
                    #         hasattr(user, "candidate_profile")
                    #         and user.candidate_profile
                    #     ):
                    #         messages.success(
                    #             request,
                    #             f"Welcome, {user.candidate_profile.first_name}!",
                    #         )
                    #         return redirect("candidate_portal_dashboard")
                    #     else:
                    #         messages.error(
                    #             request, "No candidate profile found for this user."
                    #         )
                    #         logout(request)
                else:
                    messages.error(request, "Invalid user type selected.")
            else:
                messages.error(request, "Invalid email or password.")
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = PortalLoginForm()

    context = {
        "form": form,
    }
    return render(request, "recruitment/portal_login.html", context)



def candidate_portal_dashboard(request):
    """Candidate portal dashboard"""
    if not request.user.is_authenticated:
        return redirect("account_login")

    # Get candidate profile (Person record)
    try:
        candidate = request.user.person_profile
    except:
        messages.error(request, "No candidate profile found.")
        return redirect("account_login")

    # Get candidate's applications with related job data
    applications = Application.objects.filter(
        person=candidate
    ).select_related('job').order_by('-created_at')

    # Get candidate's documents using the Person documents property
    documents = candidate.documents.order_by('-created_at')

    # Add password change form for modal
    password_form = PasswordResetForm()

    # Add document upload form for modal
    from .forms import DocumentUploadForm
    document_form = DocumentUploadForm()

    context = {
        "candidate": candidate,
        "applications": applications,
        "documents": documents,
        "password_form": password_form,
        "document_form": document_form,
    }
    return render(request, "recruitment/candidate_profile.html", context)


@login_required
def candidate_application_detail(request, slug):
    """View detailed information about a specific application"""
    if not request.user.is_authenticated:
        return redirect("account_login")

    # Get candidate profile (Person record)
    try:
        candidate = request.user.person_profile
    except:
        messages.error(request, "No candidate profile found.")
        return redirect("account_login")

    # Get the specific application and verify it belongs to this candidate
    application = get_object_or_404(
        Application.objects.select_related(
            'job', 'person'
        ).prefetch_related(
            'scheduled_interviews'  # Only prefetch interviews, not documents (Generic FK)
        ),
        slug=slug,
        person=candidate
    )

    # Get AI analysis data if available
    ai_analysis = None
    if application.ai_analysis_data:
        try:
            ai_analysis = application.ai_analysis_data.get('analysis_data', {})
        except (AttributeError, KeyError):
            ai_analysis = {}

    # Get interview details
    interviews = application.scheduled_interviews.all().order_by('-created_at')

    # Get documents
    documents = application.documents.all().order_by('-created_at')

    context = {
        "application": application,
        "candidate": candidate,
        "ai_analysis": ai_analysis,
        "interviews": interviews,
        "documents": documents,
    }
    return render(request, "recruitment/candidate_application_detail.html", context)


@agency_user_required
def agency_portal_persons_list(request):
    """Agency portal page showing all persons who come through this agency"""
    try:
        agency = request.user.agency_profile
    except Exception as e:
        print(e)
        messages.error(request, "No agency profile found.")
        return redirect("account_login")

    # Get all applications for this agency
    persons = Person.objects.filter(agency=agency)
    # persons = Application.objects.filter(
    #     hiring_agency=agency
    # ).select_related("job").order_by("-created_at")

    # Search functionality
    search_query = request.GET.get("q", "")
    if search_query:
        persons = persons.filter(
            Q(first_name__icontains=search_query)
            | Q(last_name__icontains=search_query)
            | Q(email__icontains=search_query)
            | Q(phone__icontains=search_query)
            | Q(job__title__icontains=search_query)
        )

    # Filter by stage if provided
    stage_filter = request.GET.get("stage", "")
    if stage_filter:
        persons = persons.filter(stage=stage_filter)

    # Pagination
    paginator = Paginator(persons, 20)  # Show 20 persons per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    # Get stage choices for filter dropdown
    stage_choices = Application.Stage.choices
    person_form = PersonForm()
    person_form.initial["agency"] = agency

    context = {
        "agency": agency,
        "page_obj": page_obj,
        "search_query": search_query,
        "stage_filter": stage_filter,
        "stage_choices": stage_choices,
        "total_persons": persons.count(),
        "person_form": person_form,
    }
    return render(request, "recruitment/agency_portal_persons_list.html", context)


@agency_user_required
def agency_portal_dashboard(request):
    """Agency portal dashboard showing all assignments for the agency"""
    # Get the current assignment to determine the agency
    try:
        agency = request.user.agency_profile
    except Exception as e:
        print(e)
        messages.error(request, "No agency profile found.")
        return redirect("portal_login")

    # Get ALL assignments for this agency
    assignments = (
        AgencyJobAssignment.objects.filter(agency=agency)
        .select_related("job")
        .order_by("-created_at")
    )
    current_assignment = assignments.filter(is_active=True).first()

    # Calculate statistics for each assignment
    assignment_stats = []
    for assignment in assignments:
        candidates = Application.objects.filter(
            hiring_agency=agency, job=assignment.job
        ).order_by("-created_at")

        unread_messages = 0

        assignment_stats.append(
            {
                "assignment": assignment,
                "candidates": candidates,
                "candidate_count": candidates.count(),
                "unread_messages": unread_messages,
                "days_remaining": assignment.days_remaining,
                "is_active": assignment.is_currently_active,
                "can_submit": assignment.can_submit,
            }
        )

    # Get overall statistics
    total_candidates = sum(stats["candidate_count"] for stats in assignment_stats)
    total_unread_messages = sum(stats["unread_messages"] for stats in assignment_stats)
    active_assignments = sum(1 for stats in assignment_stats if stats["is_active"])

    context = {
        "agency": agency,
        "current_assignment": current_assignment,
        "assignment_stats": assignment_stats,
        "total_assignments": assignments.count(),
        "active_assignments": active_assignments,
        "total_candidates": total_candidates,
        "total_unread_messages": total_unread_messages,
    }
    return render(request, "recruitment/agency_portal_dashboard.html", context)


@agency_user_required
def agency_portal_submit_candidate_page(request, slug):
    """Dedicated page for submitting a candidate"""
    # assignment_id = request.session.get("agency_assignment_id")
    # if not assignment_id:
    #     return redirect("agency_portal_login")

    # Get the specific assignment by slug and verify it belongs to the same agency
    # current_assignment = get_object_or_404(
    #     AgencyJobAssignment.objects.select_related("agency"), slug=slug
    # )
    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), slug=slug
    )
    current_agency=assignment.agency
    current_job=assignment.job

    if assignment.is_full:
        messages.error(request, "Maximum candidate limit reached for this assignment.")
        return redirect("agency_portal_assignment_detail", slug=assignment.slug)
    # Verify this assignment belongs to the same agency as the logged-in session
    if assignment.agency.id != assignment.agency.id:
        messages.error(
            request, "Access denied: This assignment does not belong to your agency."
        )
        return redirect("agency_portal_dashboard")

    # Check if assignment allows submission
    if not assignment.can_submit:
        messages.error(
            request,
            "Cannot submit candidates: Assignment is not active, expired, or full.",
        )
        return redirect("agency_portal_assignment_detail", slug=assignment.slug)

    # Get total submitted candidates for this assignment
    total_submitted = Application.objects.filter(
        hiring_agency=assignment.agency, job=assignment.job
    ).count()

    form = ApplicationForm(current_agency=current_agency,current_job=current_job)
    if request.method == "POST":
        form = ApplicationForm(request.POST, request.FILES,current_agency=current_agency,current_job=current_job)
        if form.is_valid():
            candidate = form.save(commit=False)

            candidate.hiring_source = "AGENCY"
            candidate.hiring_agency = assignment.agency
            candidate.save()
            assignment.increment_submission_count()
            return redirect("agency_portal_dashboard")

    form.fields["hiring_agency"].initial = assignment.agency.id
    form.fields["hiring_source"].initial = "Agency"

    form.fields["hiring_agency"].widget = HiddenInput()
    form.fields["hiring_source"].widget = HiddenInput()

    context = {
        "form": form,
        "assignment": assignment,
        "total_submitted": total_submitted,
        "job": assignment.job,
    }
    return render(request, "recruitment/agency_portal_submit_candidate.html", context)


@agency_user_required
def agency_portal_submit_candidate(request):
    """Handle candidate submission via AJAX (for embedded form)"""
    assignment_id = request.session.get("agency_assignment_id")
    if not assignment_id:
        return redirect("agency_portal_login")

    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), id=assignment_id
    )
    if assignment.is_full:
        messages.error(request, "Maximum candidate limit reached for this assignment.")
        return redirect("agency_portal_assignment_detail", slug=assignment.slug)

    # Check if assignment allows submission
    if not assignment.can_submit:
        messages.error(
            request,
            "Cannot submit candidates: Assignment is not active, expired, or full.",
        )
        return redirect("agency_portal_dashboard")

    if request.method == "POST":
        form = AgencyApplicationSubmissionForm(assignment, request.POST, request.FILES)
        if form.is_valid():
            candidate = form.save(commit=False)
            candidate.hiring_source = "AGENCY"
            candidate.hiring_agency = assignment.agency
            candidate.save()

            # Increment the assignment's submitted count
            assignment.increment_submission_count()

            if request.headers.get("X-Requested-With") == "XMLHttpRequest":
                return JsonResponse(
                    {
                        "success": True,
                        "message": f"Candidate {candidate.name} submitted successfully!",
                    }
                )
            else:
                messages.success(
                    request, f"Candidate {candidate.name} submitted successfully!"
                )
                return redirect("agency_portal_dashboard")
        else:
            if request.headers.get("X-Requested-With") == "XMLHttpRequest":
                return JsonResponse(
                    {"success": False, "message": "Please correct the errors below."}
                )
            else:
                messages.error(request, "Please correct errors below.")
    else:
        form = AgencyApplicationSubmissionForm(assignment)

    context = {
        "form": form,
        "assignment": assignment,
        "title": f"Submit Candidate for {assignment.job.title}",
        "button_text": "Submit Candidate",
    }
    return render(request, "recruitment/agency_portal_submit_candidate.html", context)


def agency_portal_assignment_detail(request, slug):
    """View details of a specific assignment - routes to admin or agency template"""
    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), slug=slug
    )

    # Check if user is authenticated and determine user type
    if request.user.is_authenticated:
        # Check if user has agency profile (agency user)
        if hasattr(request.user, 'agency_profile') and request.user.agency_profile:
            # Agency Portal User - Route to agency-specific template
            return agency_assignment_detail_agency(request, slug, assignment.id)
        else:
            # Admin User - Route to admin template
            return agency_assignment_detail_admin(request, slug)
    else:
        # Not authenticated - redirect to login
        return redirect("portal_login")


@agency_user_required
def agency_assignment_detail_agency(request, slug, assignment_id):
    """Handle agency portal assignment detail view"""
    # Get the assignment by slug and verify it belongs to same agency
    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), slug=slug
    )

    # Verify this assignment belongs to the same agency as the logged-in session
    current_assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency"), id=assignment_id
    )

    if assignment.agency.id != current_assignment.agency.id:
        messages.error(
            request, "Access denied: This assignment does not belong to your agency."
        )
        return redirect("agency_portal_dashboard")

    # Get candidates submitted by this agency for this job
    candidates = Application.objects.filter(
        hiring_agency=assignment.agency, job=assignment.job
    ).order_by("-created_at")

    # Get messages for this assignment
    messages = []

    # Mark messages as read
    # No messages to mark as read

    # Pagination for candidates
    paginator = Paginator(candidates, 20)  # Show 20 candidates per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    # Pagination for messages
    message_paginator = Paginator(messages, 15)  # Show 15 messages per page
    message_page_number = request.GET.get("message_page")
    message_page_obj = message_paginator.get_page(message_page_number)

    # Calculate progress ring offset for circular progress indicator
    total_candidates = candidates.count()
    max_candidates = assignment.max_candidates
    circumference = 326.73  # 2 * π * r where r=52

    if max_candidates > 0:
        progress_percentage = total_candidates / max_candidates
        stroke_dashoffset = circumference - (circumference * progress_percentage)
    else:
        stroke_dashoffset = circumference

    context = {
        "assignment": assignment,
        "page_obj": page_obj,
        "message_page_obj": message_page_obj,
        "total_candidates": total_candidates,
        "stroke_dashoffset": stroke_dashoffset,
    }
    return render(request, "recruitment/agency_portal_assignment_detail.html", context)


@staff_user_required
def agency_assignment_detail_admin(request, slug):
    """Handle admin assignment detail view"""
    assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency", "job"), slug=slug
    )

    # Get candidates submitted by this agency for this job
    candidates = Application.objects.filter(
        hiring_agency=assignment.agency, job=assignment.job
    ).order_by("-created_at")

    # Get access link if exists
    access_link = getattr(assignment, "access_link", None)

    # Get messages for this assignment
    messages = []

    context = {
        "assignment": assignment,
        "candidates": candidates,
        "access_link": access_link,
        "total_candidates": candidates.count(),
    }
    return render(request, "recruitment/agency_assignment_detail.html", context)


@agency_user_required
def agency_portal_edit_candidate(request, candidate_id):
    """Edit a candidate for agency portal"""
    assignment_id = request.session.get("agency_assignment_id")
    if not assignment_id:
        return redirect("agency_portal_login")

    # Get current assignment to determine agency
    current_assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency"), id=assignment_id
    )

    agency = current_assignment.agency

    # Get candidate and verify it belongs to this agency
    candidate = get_object_or_404(Application, id=candidate_id, hiring_agency=agency)

    if request.method == "POST":
        # Handle form submission
        candidate.first_name = request.POST.get("first_name", candidate.first_name)
        candidate.last_name = request.POST.get("last_name", candidate.last_name)
        candidate.email = request.POST.get("email", candidate.email)
        candidate.phone = request.POST.get("phone", candidate.phone)
        candidate.address = request.POST.get("address", candidate.address)

        # Handle resume upload if provided
        if "resume" in request.FILES:
            candidate.resume = request.FILES["resume"]

        try:
            candidate.save()
            messages.success(
                request, f"Candidate {candidate.name} updated successfully!"
            )
            return redirect(
                "agency_assignment_detail",
                slug=candidate.job.agencyjobassignment_set.first().slug,
            )
        except Exception as e:
            messages.error(request, f"Error updating candidate: {e}")

    # For GET requests or POST errors, return JSON response for AJAX
    if request.headers.get("X-Requested-With") == "XMLHttpRequest":
        return JsonResponse(
            {
                "success": True,
                "candidate": {
                    "id": candidate.id,
                    "first_name": candidate.first_name,
                    "last_name": candidate.last_name,
                    "email": candidate.email,
                    "phone": candidate.phone,
                    "address": candidate.address,
                },
            }
        )

    # Fallback for non-AJAX requests
    return redirect("agency_portal_dashboard")


@agency_user_required
def agency_portal_delete_candidate(request, candidate_id):
    """Delete a candidate for agency portal"""
    assignment_id = request.session.get("agency_assignment_id")
    if not assignment_id:
        return redirect("agency_portal_login")

    # Get current assignment to determine agency
    current_assignment = get_object_or_404(
        AgencyJobAssignment.objects.select_related("agency"), id=assignment_id
    )

    agency = current_assignment.agency

    # Get candidate and verify it belongs to this agency
    candidate = get_object_or_404(Application, id=candidate_id, hiring_agency=agency)

    if request.method == "POST":
        try:
            candidate_name = candidate.name
            candidate.delete()

            current_assignment.candidates_submitted -= 1
            current_assignment.status = current_assignment.AssignmentStatus.ACTIVE
            current_assignment.save(update_fields=["candidates_submitted", "status"])

            messages.success(
                request, f"Candidate {candidate_name} removed successfully!"
            )
            return JsonResponse({"success": True})
        except Exception as e:
            return JsonResponse({"success": False, "error": str(e)})

    # For GET requests, return error
    return JsonResponse({"success": False, "error": "Method not allowed"})


# Message Views

def message_list(request):
    """List all messages for the current user"""
    # Get filter parameters
    status_filter = request.GET.get("status", "")
    message_type_filter = request.GET.get("type", "")
    search_query = request.GET.get("q", "")

    # Base queryset - get messages where user is either sender or recipient
    message_list = (
        Message.objects.filter(Q(sender=request.user) | Q(recipient=request.user))
        .select_related("sender", "recipient", "job")
        .order_by("-created_at")
    )

    # Apply filters
    if status_filter:
        if status_filter == "read":
            message_list = message_list.filter(is_read=True)
        elif status_filter == "unread":
            message_list = message_list.filter(is_read=False)

    if message_type_filter:
        message_list = message_list.filter(message_type=message_type_filter)

    if search_query:
        message_list = message_list.filter(
            Q(subject__icontains=search_query) | Q(content__icontains=search_query)
        )

    # Pagination
    paginator = Paginator(message_list, 20)  # Show 20 messages per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    # Statistics
    total_messages = message_list.count()
    unread_messages = message_list.filter(is_read=False).count()

    context = {
        "page_obj": page_obj,
        "total_messages": total_messages,
        "unread_messages": unread_messages,
        "status_filter": status_filter,
        "type_filter": message_type_filter,
        "search_query": search_query,
    }
    if request.user.user_type != "staff":
        return render(request, "messages/candidate_message_list.html", context)
    return render(request, "messages/message_list.html", context)


@login_required
def message_detail(request, message_id):
    """View details of a specific message"""
    message = get_object_or_404(
        Message.objects.select_related("sender", "recipient", "job"), id=message_id
    )

    # Check if user has permission to view this message
    if message.sender != request.user and message.recipient != request.user:
        messages.error(request, "You don't have permission to view this message.")
        return redirect("message_list")

    # Mark as read if it was unread and user is the recipient
    if not message.is_read and message.recipient == request.user:
        message.is_read = True
        message.read_at = timezone.now()
        message.save(update_fields=["is_read", "read_at"])

    context = {
        "message": message,
    }
    if request.user.user_type != "staff":
        return render(request, "messages/candidate_message_detail.html", context)
    return render(request, "messages/message_detail.html", context)


@login_required
def message_create(request):
    """Create a new message"""
    from .email_service import EmailService
    if request.method == "POST":
        form = MessageForm(request.user, request.POST)

        if form.is_valid():
            message = form.save(commit=False)
            message.sender = request.user
            message.save()
            # Send email if message_type is 'email' and recipient has email
            if message.message_type == 'email' and message.recipient and message.recipient.email:
                try:
                    from .email_service import send_bulk_email

                    email_result = send_bulk_email(
                        subject=message.subject,
                        message=message.content,
                        recipient_list=[message.recipient.email],
                        request=request,
                        attachments=None,
                        async_task_=True,
                        from_interview=False
                    )

                    if email_result["success"]:
                        message.is_email_sent = True
                        message.email_address = message.recipient.email
                        message.save(update_fields=['is_email_sent', 'email_address'])
                        messages.success(request, "Message sent successfully via email!")
                    else:
                        messages.warning(request, f"Message saved but email failed: {email_result.get('message', 'Unknown error')}")

                except Exception as e:
                    messages.warning(request, f"Message saved but email sending failed: {str(e)}")
            else:
                messages.success(request, "Message sent successfully!")

            ["recipient", "job", "subject", "content", "message_type"]
            recipient_email = form.cleaned_data['recipient'].email # Assuming recipient is a User or Model with an 'email' field
            subject = form.cleaned_data['subject']
            custom_message = form.cleaned_data['content']
            job_id = form.cleaned_data['job'].id if 'job' in form.cleaned_data and form.cleaned_data['job'] else None
            sender_user_id = request.user.id

            task_id = async_task(
                        'recruitment.tasks.send_bulk_email_task',
                        subject,
                        custom_message, # Pass the custom message
                        [recipient_email], # Pass the specific recipient as a list of one

                        sender_user_id=sender_user_id,
                        job_id=job_id,
                        hook='recruitment.tasks.email_success_hook')

            logger.info(f"{task_id} queued.")
            return redirect("message_list")
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = MessageForm(request.user)

    context = {
        "form": form,
    }
    if request.user.user_type != "staff":
        return render(request, "messages/candidate_message_form.html", context)
    return render(request, "messages/message_form.html", context)


@login_required
def message_reply(request, message_id):
    """Reply to a message"""
    parent_message = get_object_or_404(
        Message.objects.select_related("sender", "recipient", "job"), id=message_id
    )

    # Check if user has permission to reply to this message
    if (
        parent_message.recipient != request.user
        and parent_message.sender != request.user
    ):
        messages.error(request, "You don't have permission to reply to this message.")
        return redirect("message_list")

    if request.method == "POST":
        form = MessageForm(request.user, request.POST)
        if form.is_valid():
            message = form.save(commit=False)
            message.sender = request.user
            message.parent_message = parent_message
            # Set recipient as the original sender
            message.recipient = parent_message.sender
            message.save()

            # Send email if message_type is 'email' and recipient has email
            if message.message_type == 'email' and message.recipient and message.recipient.email:
                try:
                    from .email_service import send_bulk_email

                    email_result = send_bulk_email(
                        subject=message.subject,
                        message=message.content,
                        recipient_list=[message.recipient.email],
                        request=request,
                        attachments=None,
                        async_task_=True,
                        from_interview=False
                    )

                    if email_result["success"]:
                        message.is_email_sent = True
                        message.email_address = message.recipient.email
                        message.save(update_fields=['is_email_sent', 'email_address'])
                        messages.success(request, "Reply sent successfully via email!")
                    else:
                        messages.warning(request, f"Reply saved but email failed: {email_result.get('message', 'Unknown error')}")

                except Exception as e:
                    messages.warning(request, f"Reply saved but email sending failed: {str(e)}")
            else:
                messages.success(request, "Reply sent successfully!")

            return redirect("message_detail", message_id=parent_message.id)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        # Pre-fill form with reply context
        form = MessageForm(request.user)
        form.initial["subject"] = f"Re: {parent_message.subject}"
        form.initial["recipient"] = parent_message.sender
        if parent_message.job:
            form.initial["job"] = parent_message.job
            form.initial["message_type"] = Message.MessageType.JOB_RELATED

    context = {
        "form": form,
        "parent_message": parent_message,
    }
    if request.user.user_type != "staff":
        return render(request, "messages/candidate_message_form.html", context)
    return render(request, "messages/message_form.html", context)


@login_required
def message_mark_read(request, message_id):
    """Mark a message as read"""
    message = get_object_or_404(
        Message.objects.select_related("sender", "recipient"), id=message_id
    )

    # Check if user has permission to mark this message as read
    if message.recipient != request.user:
        messages.error(request, "You can only mark messages you received as read.")
        return redirect("message_list")

    # Mark as read
    message.is_read = True
    message.read_at = timezone.now()
    message.save(update_fields=["is_read", "read_at"])

    messages.success(request, "Message marked as read.")

    # Handle HTMX requests
    if "HX-Request" in request.headers:
        return HttpResponse(status=200)  # HTMX success response

    return redirect("message_list")


@login_required
def message_mark_unread(request, message_id):
    """Mark a message as unread"""
    message = get_object_or_404(
        Message.objects.select_related("sender", "recipient"), id=message_id
    )

    # Check if user has permission to mark this message as unread
    if message.recipient != request.user:
        messages.error(request, "You can only mark messages you received as unread.")
        return redirect("message_list")

    # Mark as unread
    message.is_read = False
    message.read_at = None
    message.save(update_fields=["is_read", "read_at"])

    messages.success(request, "Message marked as unread.")

    # Handle HTMX requests
    if "HX-Request" in request.headers:
        return HttpResponse(status=200)  # HTMX success response

    return redirect("message_list")


@login_required
def message_delete(request, message_id):
    """Delete a message"""
    message = get_object_or_404(
        Message.objects.select_related("sender", "recipient"), id=message_id
    )

    # Check if user has permission to delete this message
    if message.sender != request.user and message.recipient != request.user:
        messages.error(request, "You don't have permission to delete this message.")
        return redirect("message_list")

    if request.method == "POST":
        message.delete()
        messages.success(request, "Message deleted successfully.")

        # Handle HTMX requests
        if "HX-Request" in request.headers:
            return HttpResponse(status=200)  # HTMX success response

        return redirect("message_list")

    # For GET requests, show confirmation page
    context = {
        "message": message,
        "title": "Delete Message",
        "message": f"Are you sure you want to delete this message from {message.sender.get_full_name() or message.sender.username}?",
        "cancel_url": reverse("message_detail", kwargs={"message_id": message_id}),
    }
    return render(request, "messages/message_confirm_delete.html", context)


@login_required
def api_unread_count(request):
    """API endpoint to get unread message count"""
    unread_count = Message.objects.filter(recipient=request.user, is_read=False).count()

    return JsonResponse({"unread_count": unread_count})


# Document Views
@login_required
def document_upload(request, slug):
    """Upload a document for an application or person"""
    # Handle dynamic application_id from form
    if request.method == "POST":
        actual_application_id = request.POST.get('application_id', slug)
        upload_target = request.POST.get('upload_target', 'application')  # 'application' or 'person'
    else:
        actual_application_id = slug
        upload_target = 'application'

    # Handle case where application_id is 0 (placeholder)
    if actual_application_id == '0':
        return JsonResponse({"success": False, "error": "Please select an application first"})

    if upload_target == 'person':
        # Handle Person document upload
        try:
            person = get_object_or_404(Person, id=actual_application_id)
            # Check if user owns this person (for candidate portal)
            if request.user.user_type == "candidate":
                candidate = request.user.person_profile
                if person != candidate:
                    messages.error(request, "You can only upload documents to your own profile.")
                    return JsonResponse({"success": False, "error": "Permission denied"})
        except (ValueError, Person.DoesNotExist):
            return JsonResponse({"success": False, "error": "Invalid person ID"})
    else:
        # Existing Application logic (unchanged)
        try:
            application = get_object_or_404(Application, slug=actual_application_id)
        except (ValueError, Application.DoesNotExist):
            return JsonResponse({"success": False, "error": "Invalid application ID"})

        # Check if user owns this application (for candidate portal)
        if request.user.user_type == "candidate":
            try:
                candidate = request.user.person_profile
                if application.person != candidate:
                    messages.error(request, "You can only upload documents to your own applications.")
                    return JsonResponse({"success": False, "error": "Permission denied"})
            except:
                messages.error(request, "No candidate profile found.")
                return JsonResponse({"success": False, "error": "Permission denied"})

    if request.method == "POST":
        if request.FILES.get("file"):
            if upload_target == 'person':
                # Create document for Person
                document = Document.objects.create(
                    content_object=person,  # Use Generic Foreign Key to link to Person
                    file=request.FILES["file"],
                    document_type=request.POST.get("document_type", "other"),
                    description=request.POST.get("description", ""),
                    uploaded_by=request.user,
                )
                messages.success(
                    request,
                    f'Document "{document.get_document_type_display()}" uploaded successfully!',
                )

                # Handle AJAX requests
                if request.headers.get("X-Requested-With") == "XMLHttpRequest":
                    return JsonResponse({
                        "success": True,
                        "message": "Document uploaded successfully!",
                        "document": {
                            "id": document.id,
                            "document_type": document.get_document_type_display(),
                            "description": document.description,
                            "created_at": document.created_at.strftime("%Y-%m-%d %H:%M"),
                            "file_name": document.file.name if document.file else "",
                            "file_size": f"{document.file.size / 1024:.1f} KB" if document.file else "0 KB"
                        }
                    })

                return redirect("candidate_portal_dashboard")
            else:
                # Create document for Application (existing logic)
                document = Document.objects.create(
                    content_object=application,  # Use Generic Foreign Key to link to Application
                    file=request.FILES["file"],
                    document_type=request.POST.get("document_type", "other"),
                    description=request.POST.get("description", ""),
                    uploaded_by=request.user,
                )
                messages.success(
                    request,
                    f'Document "{document.get_document_type_display()}" uploaded successfully!',
                )

                # Handle AJAX requests
                if request.headers.get("X-Requested-With") == "XMLHttpRequest":
                    return JsonResponse({
                        "success": True,
                        "message": "Document uploaded successfully!",
                        "document": {
                            "id": document.id,
                            "document_type": document.get_document_type_display(),
                            "description": document.description,
                            "created_at": document.created_at.strftime("%Y-%m-%d %H:%M"),
                            "file_name": document.file.name if document.file else "",
                            "file_size": f"{document.file.size / 1024:.1f} KB" if document.file else "0 KB"
                        }
                    })
                if upload_target == 'person':
                    return redirect("candidate_portal_dashboard")
                else:
                    return redirect("candidate_application_detail", slug=application.slug)

    # Handle GET request for AJAX
    if request.headers.get("X-Requested-With") == "XMLHttpRequest":
        return JsonResponse({"success": False, "error": "Method not allowed"})

    return redirect("candidate_detail", slug=application.job.slug)

@login_required
def document_delete(request, document_id):
    """Delete a document"""
    document = get_object_or_404(Document, id=document_id)

    # Check permission - document is now linked to Application or Person via Generic Foreign Key
    if hasattr(document.content_object, "job"):
        # Application document
        if (
            document.content_object.job.assigned_to != request.user
            and not request.user.is_superuser
        ):
            messages.error(
                request, "You don't have permission to delete this document."
            )
            return JsonResponse({"success": False, "error": "Permission denied"})
        job_slug = document.content_object.job.slug
        redirect_url = "candidate_portal_dashboard" if request.user.user_type == "candidate" else "job_detail"
    elif hasattr(document.content_object, "person"):
        # Person document
        if request.user.user_type == "candidate":
            candidate = request.user.person_profile
            if document.content_object != candidate:
                messages.error(
                    request, "You can only delete your own documents."
                )
                return JsonResponse({"success": False, "error": "Permission denied"})
        redirect_url = "candidate_portal_dashboard"
    else:
        # Handle other content object types
        messages.error(request, "You don't have permission to delete this document.")
        return JsonResponse({"success": False, "error": "Permission denied"})

    if request.method == "POST":
        file_name = document.file.name if document.file else "Unknown"
        document.delete()
        messages.success(request, f'Document "{file_name}" deleted successfully!')

        # Handle AJAX requests
        if request.headers.get("X-Requested-With") == "XMLHttpRequest":
            return JsonResponse(
                {"success": True, "message": "Document deleted successfully!"}
            )
        else:
            return redirect("candidate_detail", slug=job_slug)

    return JsonResponse({"success": False, "error": "Method not allowed"})


@login_required
def document_download(request, document_id):
    """Download a document"""
    document = get_object_or_404(Document, id=document_id)

    # Check permission - document is now linked to Application or Person via Generic Foreign Key
    if hasattr(document.content_object, "job"):
        if (
            document.content_object.job.assigned_to != request.user
            and not request.user.is_superuser
        ):
            messages.error(
                request, "You don't have permission to download this document."
            )
            return JsonResponse({"success": False, "error": "Permission denied"})
        job_slug = document.content_object.job.slug
        redirect_url = "candidate_detail" if request.user.user_type == "candidate" else "job_detail"
    elif hasattr(document.content_object, "person"):
        # Person document
        if request.user.user_type == "candidate":
            candidate = request.user.person_profile
            if document.content_object != candidate:
                messages.error(
                    request, "You can only download your own documents."
                )
                return JsonResponse({"success": False, "error": "Permission denied"})
        redirect_url = "candidate_portal_dashboard"
    else:
        # Handle other content object types
        messages.error(request, "You don't have permission to download this document.")
        return JsonResponse({"success": False, "error": "Permission denied"})

    if document.file:
        response = HttpResponse(
            document.file.read(), content_type="application/octet-stream"
        )
        response["Content-Disposition"] = f'attachment; filename="{document.file.name}"'
        return response

    return JsonResponse({"success": False, "error": "File not found"})

    if document.file:
        response = HttpResponse(
            document.file.read(), content_type="application/octet-stream"
        )
        response["Content-Disposition"] = f'attachment; filename="{document.file.name}"'
        return response

    return JsonResponse({"success": False, "error": "File not found"})


@login_required
def portal_logout(request):
    """Logout from portal"""
    logout(request)

    messages.success(request, "You have been logged out.")
    return redirect("portal_login")


@login_required
def agency_access_link_deactivate(request, slug):
    """Deactivate an agency access link"""
    access_link = get_object_or_404(
        AgencyAccessLink.objects.select_related(
            "assignment__agency", "assignment__job"
        ),
        slug=slug,
    )

    if request.method == "POST":
        access_link.is_active = False
        access_link.save(update_fields=["is_active"])

        messages.success(
            request,
            f"Access link for {access_link.assignment.agency.name} - {access_link.assignment.job.title} has been deactivated.",
        )

        # Handle HTMX requests
        if "HX-Request" in request.headers:
            return HttpResponse(status=200)  # HTMX success response

        return redirect("agency_assignment_detail", slug=access_link.assignment.slug)

    # For GET requests, show confirmation page
    context = {
        "access_link": access_link,
        "title": "Deactivate Access Link",
        "message": f"Are you sure you want to deactivate the access link for {access_link.assignment.agency.name}?",
        "cancel_url": reverse(
            "agency_assignment_detail", kwargs={"slug": access_link.assignment.slug}
        ),
    }
    return render(request, "recruitment/agency_access_link_confirm.html", context)


@login_required
def agency_access_link_reactivate(request, slug):
    """Reactivate an agency access link"""
    access_link = get_object_or_404(
        AgencyAccessLink.objects.select_related(
            "assignment__agency", "assignment__job"
        ),
        slug=slug,
    )

    if request.method == "POST":
        access_link.is_active = True
        access_link.save(update_fields=["is_active"])

        messages.success(
            request,
            f"Access link for {access_link.assignment.agency.name} - {access_link.assignment.job.title} has been reactivated.",
        )

        # Handle HTMX requests
        if "HX-Request" in request.headers:
            return HttpResponse(status=200)  # HTMX success response

        return redirect("agency_assignment_detail", slug=access_link.assignment.slug)

    # For GET requests, show confirmation page
    context = {
        "access_link": access_link,
        "title": "Reactivate Access Link",
        "message": f"Are you sure you want to reactivate the access link for {access_link.assignment.agency.name}?",
        "cancel_url": reverse(
            "agency_assignment_detail", kwargs={"slug": access_link.assignment.slug}
        ),
    }
    return render(request, "recruitment/agency_access_link_confirm.html", context)


@agency_user_required
def api_candidate_detail(request, candidate_id):
    """API endpoint to get candidate details for agency portal"""
    try:
        # Get candidate from session-based agency access
        assignment_id = request.session.get("agency_assignment_id")
        if not assignment_id:
            return JsonResponse({"success": False, "error": "Access denied"})

        # Get current assignment to determine agency
        current_assignment = get_object_or_404(
            AgencyJobAssignment.objects.select_related("agency"), id=assignment_id
        )

        agency = current_assignment.agency

        # Get candidate and verify it belongs to this agency
        candidate = get_object_or_404(
            Application, id=candidate_id, hiring_agency=agency
        )

        # Return candidate data
        response_data = {
            "success": True,
            "id": candidate.id,
            "first_name": candidate.first_name,
            "last_name": candidate.last_name,
            "email": candidate.email,
            "phone": candidate.phone,
            "address": candidate.address,
        }

        return JsonResponse(response_data)

    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)})


@staff_user_required
def compose_candidate_email(request, job_slug):
    """Compose email to participants about a candidate"""
    from .email_service import send_bulk_email

    job = get_object_or_404(JobPosting, slug=job_slug)

    # # candidate = get_object_or_404(Application, slug=candidate_slug, job=job)
    # if request.method == "POST":
    #     form = CandidateEmailForm(job, candidate, request.POST)
    candidate_ids=request.GET.getlist('candidate_ids')
    candidates=Application.objects.filter(id__in=candidate_ids)


    if request.method == 'POST':

        candidate_ids = request.POST.getlist('candidate_ids')
        candidates=Application.objects.filter(id__in=candidate_ids)
        form = CandidateEmailForm(job, candidates, request.POST)
        if form.is_valid():
            print("form is   valid ...")
            # Get email addresses
            email_addresses = form.get_email_addresses()


            if not email_addresses:
                messages.error(request, 'No email selected')
                referer = request.META.get('HTTP_REFERER')

                if referer:
                    # Redirect back to the referring page
                    return redirect(referer)
                else:

                    return redirect('dashboard')


            message = form.get_formatted_message()
            subject = form.cleaned_data.get('subject')

            # Send emails using email service (no attachments, synchronous to avoid pickle issues)

            email_result = send_bulk_email(  #
                subject=subject,
                message=message,
                recipient_list=email_addresses,
                request=request,
                attachments=None,
                async_task_=True,  # Changed to False to avoid pickle issues
                from_interview=False,
                job=job
            )
            
            if email_result["success"]:
                for candidate in candidates:
                    if hasattr(candidate, 'person') and candidate.person:
                        try:
                            Message.objects.create(
                                sender=request.user,
                                recipient=candidate.person.user,
                                subject=subject,
                                content=message,
                                job=job,
                                message_type='email',
                                is_email_sent=True,
                                email_address=candidate.person.email if candidate.person.email else candidate.email
                            )

                        except Exception as e:
                            # Log error but don't fail the entire process
                            print(f"Error creating message")

                messages.success(
                    request,
                    f"Email will be sent shortly to recipient(s)",
                )
                response = HttpResponse(status=200)
                response.headers["HX-Refresh"] = "true"
                return response
                # return redirect("candidate_interview_view", slug=job.slug)
            else:
                messages.error(
                    request,
                    f"Failed to send email: {email_result.get('message', 'Unknown error')}",
                )

                # For HTMX requests, return error response
                if "HX-Request" in request.headers:
                    return JsonResponse(
                        {
                            "success": False,
                            "error": email_result.get(
                                "message", "Failed to send email"
                            ),
                        }
                    )

                return render(
                    request,
                    "includes/email_compose_form.html",
                    {"form": form, "job": job, "candidate": candidates},
                )



        else:
            # Form validation errors
            messages.error(request, "Please correct the errors below.")

            # For HTMX requests, return error response
            if "HX-Request" in request.headers:
                return JsonResponse(
                    {
                        "success": False,
                        "error": "Please correct the form errors and try again.",
                    }
                )

            return render(
                request,
                "includes/email_compose_form.html",
                {"form": form, "job": job, "candidates": candidates},
                )

    else:
        # GET request - show the form
        form = CandidateEmailForm(job, candidates)

        return render(
            request,
            "includes/email_compose_form.html",
            # {"form": form, "job": job, "candidates": candidates},
             {"form": form,"job":job},
        )



# Source CRUD Views
@staff_user_required
def source_list(request):
    """List all sources with search and pagination"""
    search_query = request.GET.get("q", "")
    sources = Source.objects.all()

    if search_query:
        sources = sources.filter(
            Q(name__icontains=search_query)
            | Q(source_type__icontains=search_query)
            | Q(description__icontains=search_query)
        )

    # Order by most recently created
    sources = sources.order_by("-created_at")

    # Pagination
    paginator = Paginator(sources, 15)  # Show 15 sources per page
    page_number = request.GET.get("page")
    page_obj = paginator.get_page(page_number)

    context = {
        "page_obj": page_obj,
        "search_query": search_query,
        "total_sources": sources.count(),
    }
    return render(request, "recruitment/source_list.html", context)


@staff_user_required
def source_create(request):
    """Create a new source"""
    if request.method == "POST":
        form = SourceForm(request.POST)
        if form.is_valid():
            source = form.save()
            messages.success(request, f'Source "{source.name}" created successfully!')
            return redirect("source_detail", slug=source.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = SourceForm()

    context = {
        "form": form,
        "title": "Create New Source",
        "button_text": "Create Source",
    }
    return render(request, "recruitment/source_form.html", context)


@staff_user_required
def source_detail(request, slug):
    """View details of a specific source"""
    source = get_object_or_404(Source, slug=slug)

    # Get integration logs for this source
    integration_logs = source.integration_logs.order_by("-created_at")[
        :10
    ]  # Show recent 10 logs

    # Statistics
    total_logs = source.integration_logs.count()
    successful_logs = source.integration_logs.filter(method="POST").count()
    failed_logs = source.integration_logs.filter(
        method="POST", status_code__gte=400
    ).count()

    context = {
        "source": source,
        "integration_logs": integration_logs,
        "total_logs": total_logs,
        "successful_logs": successful_logs,
        "failed_logs": failed_logs,
    }
    return render(request, "recruitment/source_detail.html", context)


@staff_user_required
def source_update(request, slug):
    """Update an existing source"""
    source = get_object_or_404(Source, slug=slug)

    if request.method == "POST":
        form = SourceForm(request.POST, instance=source)
        if form.is_valid():
            source = form.save()
            messages.success(request, f'Source "{source.name}" updated successfully!')
            return redirect("source_detail", slug=source.slug)
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = SourceForm(instance=source)

    context = {
        "form": form,
        "source": source,
        "title": f"Edit Source: {source.name}",
        "button_text": "Update Source",
    }
    return render(request, "recruitment/source_form.html", context)


@staff_user_required
def source_delete(request, slug):
    """Delete a source"""
    source = get_object_or_404(Source, slug=slug)

    if request.method == "POST":
        source_name = source.name
        source.delete()
        messages.success(request, f'Source "{source_name}" deleted successfully!')
        return redirect("source_list")

    context = {
        "source": source,
        "title": "Delete Source",
        "message": f'Are you sure you want to delete the source "{source.name}"?',
        "cancel_url": reverse("source_detail", kwargs={"slug": source.slug}),
    }
    return render(request, "recruitment/source_confirm_delete.html", context)


@login_required
def source_generate_keys(request, slug):
    """Generate new API keys for a source"""
    source = get_object_or_404(Source, slug=slug)

    if request.method == "POST":
        # Generate new API key and secret
        from .forms import generate_api_key, generate_api_secret

        source.api_key = generate_api_key()
        source.api_secret = generate_api_secret()
        source.save(update_fields=["api_key", "api_secret"])

        messages.success(request, f'New API keys generated for "{source.name}"!')
        return redirect("source_detail", slug=source.slug)

    # For GET requests, show confirmation page
    context = {
        "source": source,
        "title": "Generate New API Keys",
        "message": f'Are you sure you want to generate new API keys for "{source.name}"? This will invalidate the existing keys.',
        "cancel_url": reverse("source_detail", kwargs={"slug": source.slug}),
    }
    return render(request, "recruitment/source_confirm_generate_keys.html", context)


@login_required
def source_toggle_status(request, slug):
    """Toggle active status of a source"""
    source = get_object_or_404(Source, slug=slug)

    if request.method == "POST":
        source.is_active = not source.is_active
        source.save(update_fields=["is_active"])

        status_text = "activated" if source.is_active else "deactivated"
        messages.success(request, f'Source "{source.name}" has been {status_text}!')

        # Handle HTMX requests
        if "HX-Request" in request.headers:
            return HttpResponse(status=200)  # HTMX success response

        return redirect("source_detail", slug=source.slug)

    # For GET requests, return error
    return JsonResponse({"success": False, "error": "Method not allowed"})


def candidate_signup(request, slug):
    from .forms import CandidateSignupForm

    form_template = get_object_or_404(FormTemplate, slug=slug)
    job = form_template.job

    if request.method == "POST":
        form = CandidateSignupForm(request.POST)
        if form.is_valid():
            try:
                first_name = form.cleaned_data["first_name"]
                last_name = form.cleaned_data["last_name"]
                email = form.cleaned_data["email"]
                phone = form.cleaned_data["phone"]
                gender = form.cleaned_data["gender"]
                nationality = form.cleaned_data["nationality"]
                address = form.cleaned_data["address"]
                # gpa = form.cleaned_data["gpa"]
                password = form.cleaned_data["password"]

                user = User.objects.create_user(
                    username = email,email=email,first_name=first_name,last_name=last_name,phone=phone,user_type="candidate"
                )
                user.set_password(password)
                user.save()
                Person.objects.create(
                    first_name=first_name,
                    last_name=last_name,
                    email=email,
                    phone=phone,
                    gender=gender,
                    nationality=nationality,
                    # gpa=gpa,
                    address=address,
                    user = user
                )
                login(request, user,backend='django.contrib.auth.backends.ModelBackend')

                return redirect("application_submit_form", template_slug=slug)
            except Exception as e:
                messages.error(request, f"Error creating application: {str(e)}")
                return render(
                    request,
                    "recruitment/candidate_signup.html",
                    {"form": form, "job": job},
                )

    form = CandidateSignupForm()
    return render(
        request, "recruitment/candidate_signup.html", {"form": form, "job": job}
    )


from .forms import InterviewParticpantsForm


# def create_interview_participants(request, slug):
#     schedule_interview = get_object_or_404(ScheduledInterview, slug=slug)
#     interview_slug = schedule_interview.zoom_meeting.slug
#     if request.method == "POST":
#         form = InterviewParticpantsForm(request.POST, instance=schedule_interview)
#         if form.is_valid():
#             # Save the main Candidate object, but don't commit to DB yet
#             candidate = form.save(commit=False)
#             candidate.save()
#             # This is important for ManyToMany fields: save the many-to-many data
#             form.save_m2m()
#             return redirect(
#                 "meeting_details", slug=interview_slug
#             )  # Redirect to a success page
#     else:
#         form = InterviewParticpantsForm(instance=schedule_interview)

#     return render(
#         request, "interviews/interview_participants_form.html", {"form": form}
#     )

def create_interview_participants(request, slug):
    """
    Manage participants for a ScheduledInterview.
    Uses interview_pk because ScheduledInterview has no slug.
    """
    schedule_interview = get_object_or_404(ScheduledInterview, slug=slug)

    # Get the slug from the related InterviewLocation (the "meeting")
    meeting_slug = schedule_interview.interview_location.slug  # ✅ Correct

    if request.method == "POST":
        form = InterviewParticpantsForm(request.POST, instance=schedule_interview)
        if form.is_valid():
            form.save()  # No need for commit=False — it's not a create, just update
            messages.success(request, "Participants updated successfully.")
            return redirect("meeting_details", slug=meeting_slug)
    else:
        form = InterviewParticpantsForm(instance=schedule_interview)

    return render(
        request,
        "interviews/interview_participants_form.html",
        {"form": form, "interview": schedule_interview}
    )


from django.core.mail import send_mail


def send_interview_email(request, slug):
    from .email_service import send_bulk_email

    interview = get_object_or_404(ScheduledInterview, slug=slug)

    # 2. Retrieve the required data for the form's constructor
    candidate = interview.application
    job = interview.job
    meeting = interview.interview_location
    participants = list(interview.participants.all()) + list(
        interview.system_users.all()
    )
    external_participants = list(interview.participants.all())
    system_participants = list(interview.system_users.all())

    participant_emails = [p.email for p in participants if hasattr(p, "email")]
    print(participant_emails)
    total_recipients = 1 + len(participant_emails)

    # --- POST REQUEST HANDLING ---
    if request.method == "POST":
        form = InterviewEmailForm(
            request.POST,
            candidate=candidate,
            external_participants=external_participants,
            system_participants=system_participants,
            meeting=meeting,
            job=job,
        )
      
        if form.is_valid():
            # 4. Extract cleaned data
            subject = form.cleaned_data["subject"]
            msg_candidate = form.cleaned_data["message_for_candidate"]
            msg_agency = form.cleaned_data["message_for_agency"]
            msg_participants = form.cleaned_data["message_for_participants"]

            # --- SEND EMAILS Candidate or agency---
            if candidate.belong_to_an_agency:
                email=candidate.hiring_agency.email
                print(email)
                send_mail(
                    subject,
                    msg_agency,
                    settings.DEFAULT_FROM_EMAIL,
                    [candidate.hiring_agency.email],
                    fail_silently=False,
                )
            else:
                send_mail(
                    subject,
                    msg_candidate,
                    settings.DEFAULT_FROM_EMAIL,
                    [candidate.person.email],
                    fail_silently=False,
                )

            email_result = send_bulk_email(
                subject=subject,
                message=msg_participants,
                recipient_list=participant_emails,
                request=request,
                attachments=None,
                async_task_=True,  # Changed to False to avoid pickle issues,
                from_interview=True,
                job=job

            )

            if email_result["success"]:
                # Create Message records for each participant after successful email send
                messages_created = 0
                for participant in participants:
                    if hasattr(participant, 'user') and participant.user:
                        try:
                            Message.objects.create(
                                sender=request.user,
                                recipient=participant.user,
                                subject=subject,
                                content=msg_participants,
                                job=job,
                                message_type='email',
                                is_email_sent=True,
                                email_address=participant.email if hasattr(participant, 'email') else ''
                            )
                            messages_created += 1
                        except Exception as e:
                            # Log error but don't fail the entire process
                            print(f"Error creating message for {participant.email if hasattr(participant, 'email') else participant}: {e}")

                messages.success(
                    request,
                    f"Email will be sent shortly to {total_recipients} recipient(s).",
                )

                return redirect("list_meetings")
            else:
                messages.error(
                    request,
                    f"Failed to send email: {email_result.get('message', 'Unknown error')}",
                )
                return redirect("list_meetings")
        else:
          
            error_msg = "Failed to send email. Please check the form for errors."
            print(form.errors)
            messages.error(request, error_msg)
            return redirect("meeting_details", slug=meeting.slug) 
    return redirect("meeting_details", slug=meeting.slug)


# def schedule_interview_location_form(request,slug):
#     schedule=get_object_or_404(InterviewSchedule,slug=slug)
#     if request.method=='POST':
#         form=InterviewScheduleLocationForm(request.POST,instance=schedule)
#         form.save()
#         return redirect('list_meetings')
#     else:
#         form=InterviewScheduleLocationForm(instance=schedule)
#         return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})


class MeetingListView(ListView):
    """
    A unified view to list both Remote and Onsite Scheduled Interviews.
    """
    model = ScheduledInterview
    template_name = "meetings/list_meetings.html"
    context_object_name = "meetings"
    paginate_by = 100

    def get_queryset(self):
        # Start with a base queryset, ensuring an InterviewLocation link exists.
        queryset = super().get_queryset().filter(interview_location__isnull=False).select_related(
            'interview_location',
            'job',
            'application__person',
            'application',
        ).prefetch_related(
            'interview_location__zoommeetingdetails',
            'interview_location__onsitelocationdetails',
        )
        # Note: Printing the queryset here can consume memory for large sets.

        # Get filters from GET request
        search_query = self.request.GET.get("q")
        status_filter = self.request.GET.get("status")
        candidate_name_filter = self.request.GET.get("candidate_name")
        type_filter = self.request.GET.get("type")
        print(type_filter)

        # 2. Type Filter: Filter based on the base InterviewLocation's type
        if type_filter:
            # Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote')
            normalized_type = type_filter.title()
            print(normalized_type)
            # Assuming InterviewLocation.LocationType is accessible/defined
            if normalized_type in ['Remote', 'Onsite']:
                queryset = queryset.filter(interview_location__location_type=normalized_type)
                print(queryset)

        # 3. Search by Topic (stored on InterviewLocation)
        if search_query:
            queryset = queryset.filter(interview_location__topic__icontains=search_query)

        # 4. Status Filter
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        # 5. Candidate Name Filter
        if candidate_name_filter:
            queryset = queryset.filter(
                Q(application__person__first_name__icontains=candidate_name_filter) |
                Q(application__person__last_name__icontains=candidate_name_filter)
            )

        return queryset.order_by("-interview_date", "-interview_time")


    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Pass filters back to the template for retention
        context["search_query"] = self.request.GET.get("q", "")
        context["status_filter"] = self.request.GET.get("status", "")
        context["candidate_name_filter"] = self.request.GET.get("candidate_name", "")
        context["type_filter"] = self.request.GET.get("type", "")


        # CORRECTED: Pass the status choices from the model class for the filter dropdown
        context["status_choices"] = self.model.InterviewStatus.choices

        meetings_data = []

        for interview in context.get(self.context_object_name, []):
            location = interview.interview_location
            details = None

            if not location:
                continue

            # Determine and fetch the CONCRETE details object (prefetched)
            if location.location_type == location.LocationType.REMOTE:
                details = getattr(location, 'zoommeetingdetails', None)
            elif location.location_type == location.LocationType.ONSITE:
                details = getattr(location, 'onsitelocationdetails', None)

            # Combine date and time for template display/sorting
            start_datetime = None
            if interview.interview_date and interview.interview_time:
                start_datetime = datetime.combine(interview.interview_date, interview.interview_time)

            # SUCCESS: Build the data dictionary
            meetings_data.append({
                'interview': interview,
                'location': location,
                'details': details,
                'type': location.location_type,
                'topic': location.topic,
                'slug': interview.slug,
                'start_time': start_datetime, # Combined datetime object
                # Duration should ideally be on ScheduledInterview or fetched from details
                'duration': getattr(details, 'duration', 'N/A'),
                # Use details.join_url and fallback to None, if Remote
                'join_url': getattr(details, 'join_url', None) if location.location_type == location.LocationType.REMOTE else None,
                'meeting_id': getattr(details, 'meeting_id', None),
                # Use the primary status from the ScheduledInterview record
                'status': interview.status,
            })

        context["meetings_data"] = meetings_data

        return context

def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
    """Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails)."""
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_id)

    # Fetch the OnsiteLocationDetails instance, ensuring it belongs to this candidate.
    # We use the reverse relationship: onsitelocationdetails -> interviewlocation -> scheduledinterview -> application
    # The 'interviewlocation_ptr' is the foreign key field name if OnsiteLocationDetails is a proxy/multi-table inheritance model.
    onsite_meeting = get_object_or_404(
        OnsiteLocationDetails,
        pk=meeting_id,
        # Correct filter: Use the reverse link through the ScheduledInterview model.
        # This assumes your ScheduledInterview model links back to a generic InterviewLocation base.
        interviewlocation_ptr__scheduled_interview__application=candidate
    )

    if request.method == 'POST':
        form = OnsiteReshuduleForm(request.POST, instance=onsite_meeting)

        if form.is_valid():
            instance = form.save(commit=False)

            if instance.start_time < timezone.now():
                messages.error(request, "Start time must be in the future for rescheduling.")
                return render(request, "meetings/reschedule_onsite.html", {"form": form, "job": job, "candidate": candidate, "meeting": onsite_meeting})

            # Update parent status
            try:
                # Retrieve the ScheduledInterview instance via the reverse relationship
                scheduled_interview = ScheduledInterview.objects.get(
                    interview_location=instance.interviewlocation_ptr # Use the base model FK
                )
                scheduled_interview.status = ScheduledInterview.InterviewStatus.SCHEDULED
                scheduled_interview.save()
            except ScheduledInterview.DoesNotExist:
                messages.warning(request, "Parent schedule record not found. Status not updated.")

            instance.save()
            messages.success(request, "Onsite meeting successfully rescheduled! ✅")

            return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug}))

    else:
        form = OnsiteReshuduleForm(instance=onsite_meeting)

    context = {
        "form": form,
        "job": job,
        "candidate": candidate,
        "meeting": onsite_meeting
    }
    return render(request, "meetings/reschedule_onsite_meeting.html", context)


# recruitment/views.py

@staff_user_required
def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
    """
    Deletes a specific Onsite Location Details instance.
    This does not require an external API call.
    """
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_pk)

    # Target the specific Onsite meeting details instance
    meeting = get_object_or_404(OnsiteLocationDetails, pk=meeting_id)

    if request.method == "POST":
        # Delete the local Django object.
        # This deletes the base InterviewLocation and updates the ScheduledInterview FK.
        meeting.delete()
        messages.success(request, f"Onsite meeting for {candidate.name} deleted successfully.")

        return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))

    context = {
        "job": job,
        "candidate": candidate,
        "meeting": meeting,
        "location_type": "Onsite",
        "delete_url": reverse(
            "delete_onsite_meeting_for_candidate", # Use the specific new URL name
            kwargs={
                "slug": job.slug,
                "candidate_pk": candidate_pk,
                "meeting_id": meeting_id,
            },
        ),
    }
    return render(request, "meetings/delete_meeting_form.html", context)



def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk):
    """
    Handles scheduling a NEW Onsite Interview for a candidate using OnsiteScheduleForm.
    """
    job = get_object_or_404(JobPosting, slug=slug)
    candidate = get_object_or_404(Application, pk=candidate_pk)

    action_url = reverse('schedule_onsite_meeting_for_candidate',
                         kwargs={'slug': job.slug, 'candidate_pk': candidate.pk})

    if request.method == 'POST':
        # Use the new form
        form = OnsiteScheduleForm(request.POST)
        if form.is_valid():

            cleaned_data = form.cleaned_data

            # 1. Create OnsiteLocationDetails
            onsite_loc = OnsiteLocationDetails(
                topic=cleaned_data['topic'],
                physical_address=cleaned_data['physical_address'],
                room_number=cleaned_data['room_number'],
                start_time=cleaned_data['start_time'],
                duration=cleaned_data['duration'],
                status=OnsiteLocationDetails.Status.WAITING,
                location_type=InterviewLocation.LocationType.ONSITE,
            )
            onsite_loc.save()

            # 2. Extract Date and Time
            interview_date = cleaned_data['start_time'].date()
            interview_time = cleaned_data['start_time'].time()

            # 3. Create ScheduledInterview linked to the new location
            # Use cleaned_data['application'] and cleaned_data['job'] from the form
            ScheduledInterview.objects.create(
                application=cleaned_data['application'],
                job=cleaned_data['job'],
                interview_location=onsite_loc,
                interview_date=interview_date,
                interview_time=interview_time,
                status=ScheduledInterview.InterviewStatus.SCHEDULED,
            )

            messages.success(request, "Onsite interview scheduled successfully. ✅")
            return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug}))

    else:
        # GET Request: Initialize the hidden fields with the correct objects
        initial_data = {
            'application': candidate, # Pass the object itself for ModelChoiceField
            'job': job,               # Pass the object itself for ModelChoiceField
        }
        # Use the new form
        form = OnsiteScheduleForm(initial=initial_data)

    context = {
        "form": form,
        "job": job,
        "candidate": candidate,
        "action_url": action_url,
    }

    return render(request, "meetings/schedule_onsite_meeting_form.html", context)



from django.http import Http404


def meeting_details(request, slug):
    # Fetch the meeting (InterviewLocation or subclass) by slug
    meeting = get_object_or_404(
        InterviewLocation.objects.select_related(
            'scheduled_interview__application__person',
            'scheduled_interview__job',
            'zoommeetingdetails',
            'onsitelocationdetails',
        ).prefetch_related(
            'scheduled_interview__participants',
            'scheduled_interview__system_users',
            'scheduled_interview__notes',
        ),
        slug=slug
    )

    try:
        interview = meeting.scheduled_interview
    except ScheduledInterview.DoesNotExist:
        raise Http404("No interview is associated with this meeting.")

    candidate = interview.application
    job = interview.job

    external_participants = interview.participants.all()
    system_participants = interview.system_users.all()
    total_participants = external_participants.count() + system_participants.count()

    # Forms for modals
    participant_form = InterviewParticpantsForm(instance=interview)


    email_form = InterviewEmailForm(
    candidate=candidate,
    external_participants=external_participants,  # QuerySet of Participants
    system_participants=system_participants,      # QuerySet of Users
    meeting=meeting,  # ← This is InterviewLocation (e.g., ZoomMeetingDetails)
    job=job,
     )

    context = {
        'meeting': meeting,
        'interview': interview,
        'candidate': candidate,
        'job': job,
        'external_participants': external_participants,
        'system_participants': system_participants,
        'total_participants': total_participants,
        'form': participant_form,
        'email_form': email_form,
    }

    return render(request, 'interviews/detail_interview.html', context)

