import json
import csv
from datetime import datetime
from django.shortcuts import render, get_object_or_404,redirect
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from django.db.models.fields.json import KeyTextTransform
from recruitment.utils import json_to_markdown_table
from django.db.models import Count, Avg, F, FloatField
from django.db.models.functions import Cast
from django.db.models.functions import Coalesce, Cast, Replace, NullIf
from . import models
from django.utils.translation import get_language
from . import forms
from django.contrib.auth.decorators import login_required
import ast
from django.template.loader import render_to_string
from django.utils.text import slugify
# from .dashboard import get_dashboard_data
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView
# JobForm removed - using JobPostingForm instead
from django.urls import reverse_lazy
from django.db.models import FloatField
from django.db.models import F, IntegerField, Count, Avg, Sum, Q, ExpressionWrapper, fields, Value,CharField
from django.db.models.functions import Cast, Coalesce, TruncDate
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.utils import timezone
from datetime import timedelta
import json

# Add imports for user type restrictions
from recruitment.decorators import StaffRequiredMixin, staff_user_required


from datastar_py.django import (
    DatastarResponse,
    ServerSentEventGenerator as SSE,
    read_signals,
)
# from rich import print
from rich.markdown import CodeBlock

class JobListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
    model = models.JobPosting
    template_name = 'jobs/job_list.html'
    context_object_name = 'jobs'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset().order_by('-created_at')
        # Handle search
        search_query = self.request.GET.get('search', '')
        if search_query:
            queryset = queryset.filter(
                Q(title__icontains=search_query) |
                Q(description__icontains=search_query) |
                Q(department__icontains=search_query)
            )

        # Filter for non-staff users
        # if not self.request.user.is_staff:
        #     queryset = queryset.filter(status='Published')

        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        context['lang'] = get_language()
        context['status_filter']=self.request.GET.get('status')
        return context


class JobCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, CreateView):
    model = models.JobPosting
    form_class = forms.JobPostingForm
    template_name = 'jobs/create_job.html'
    success_url = reverse_lazy('job_list')
    success_message = 'Job created successfully.'


class JobUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, UpdateView):
    model = models.JobPosting
    form_class = forms.JobPostingForm
    template_name = 'jobs/edit_job.html'
    success_url = reverse_lazy('job_list')
    success_message = 'Job updated successfully.'
    slug_url_kwarg = 'slug'


class JobDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
    model = models.JobPosting
    template_name = 'jobs/partials/delete_modal.html'
    success_url = reverse_lazy('job_list')
    success_message = 'Job deleted successfully.'
    slug_url_kwarg = 'slug'

class JobApplicationListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
    model = models.Application
    template_name = 'jobs/job_candidates_list.html'
    context_object_name = 'applications'
    paginate_by = 10

    def get_queryset(self):
        # Get the job by slug
        self.job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])

        # Filter candidates for this specific job
        queryset = models.Application.objects.filter(job=self.job)

        if self.request.GET.get('stage'):
            stage=self.request.GET.get('stage')
            queryset=queryset.filter(stage=stage)


        # Handle search
        search_query = self.request.GET.get('search', '')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(email__icontains=search_query) |
                Q(phone__icontains=search_query) |
                Q(stage__icontains=search_query)
            )

        # Filter for non-staff users
        if not self.request.user.is_staff:
            return models.Application.objects.none()  # Restrict for non-staff

        return queryset.order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        context['job'] = getattr(self, 'job', None)
        return context


class ApplicationListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
    model = models.Application
    template_name = 'recruitment/candidate_list.html'
    context_object_name = 'applications'
    paginate_by = 100

    def get_queryset(self):
        queryset = super().get_queryset()

        # Handle search
        search_query = self.request.GET.get('search', '')
        job = self.request.GET.get('job', '')
        stage = self.request.GET.get('stage', '')
        if search_query:
            queryset = queryset.filter(
                Q(person__first_name__icontains=search_query) |
                Q(person__last_name__icontains=search_query) |
                Q(person__email__icontains=search_query) |
                Q(person__phone__icontains=search_query) 
            )
        if job:
            queryset = queryset.filter(job__slug=job)
        if stage:
            queryset = queryset.filter(stage=stage)
        # Filter for non-staff users
        # if not self.request.user.is_staff:
        #     return models.Application.objects.none()  # Restrict for non-staff

        return queryset.order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        context['job_filter'] = self.request.GET.get('job', '')
        context['stage_filter'] = self.request.GET.get('stage', '')
        context['available_jobs'] = models.JobPosting.objects.all().order_by('created_at').distinct()
        return context


class ApplicationCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, CreateView):
    model = models.Application
    form_class = forms.ApplicationForm
    template_name = 'recruitment/candidate_create.html'
    success_url = reverse_lazy('candidate_list')
    success_message = 'Candidate created successfully.'

    def get_initial(self):
        initial = super().get_initial()
        if 'slug' in self.kwargs:
            job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
            initial['job'] = job
        return initial

    def form_valid(self, form):
        if 'slug' in self.kwargs:
            job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
            form.instance.job = job
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.method == 'GET':
            context['person_form'] = forms.PersonForm()
        return context

class ApplicationUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, UpdateView):
    model = models.Application
    form_class = forms.ApplicationForm
    template_name = 'recruitment/candidate_update.html'
    success_url = reverse_lazy('candidate_list')
    success_message = 'Candidate updated successfully.'
    slug_url_kwarg = 'slug'


class ApplicationDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
    model = models.Application
    template_name = 'recruitment/candidate_delete.html'
    success_url = reverse_lazy('candidate_list')
    success_message = 'Candidate deleted successfully.'
    slug_url_kwarg = 'slug'


def retry_scoring_view(request,slug):
    from django_q.tasks import async_task

    application = get_object_or_404(models.Application, slug=slug)

    async_task(
        'recruitment.tasks.handle_reume_parsing_and_scoring',
        application.pk,
        hook='recruitment.hooks.callback_ai_parsing',
        sync=True,
    )
    return redirect('candidate_detail', slug=application.slug)



@login_required
@staff_user_required
def training_list(request):
    materials = models.TrainingMaterial.objects.all().order_by('-created_at')
    return render(request, 'recruitment/training_list.html', {'materials': materials})


@login_required
@staff_user_required
def candidate_detail(request, slug):
    from rich.json import JSON
    candidate = get_object_or_404(models.Application, slug=slug)
    try:
        parsed = ast.literal_eval(candidate.parsed_summary)
    except:
        parsed = {}

    # Create stage update form for staff users
    stage_form = None
    if request.user.is_staff:
        stage_form = forms.ApplicationStageForm()



    # parsed = JSON(json.dumps(parsed), indent=2, highlight=True, skip_keys=False, ensure_ascii=False, check_circular=True, allow_nan=True, default=None, sort_keys=False)
    # parsed = json_to_markdown_table([parsed])
    return render(request, 'recruitment/candidate_detail.html', {
        'candidate': candidate,
        'parsed': parsed,
        'stage_form': stage_form,
    })


@login_required
@staff_user_required
def candidate_resume_template_view(request, slug):
    """Display formatted resume template for a candidate"""
    application = get_object_or_404(models.Application, slug=slug)

    if not request.user.is_staff:
        messages.error(request, _("You don't have permission to view this page."))
        return redirect('candidate_list')

    return render(request, 'recruitment/candidate_resume_template.html', {
        'application': application
    })

@login_required
@staff_user_required
def candidate_update_stage(request, slug):
    """Handle HTMX stage update requests"""
    application = get_object_or_404(models.Application, slug=slug)
    form = forms.ApplicationStageForm(request.POST, instance=application)
    if form.is_valid():
        stage_value = form.cleaned_data['stage']
        application.stage = stage_value
        application.save(update_fields=['stage'])
        messages.success(request,"application Stage Updated")
        return redirect("candidate_detail",slug=application.slug)

class TrainingListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
    model = models.TrainingMaterial
    template_name = 'recruitment/training_list.html'
    context_object_name = 'materials'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()

        # Handle search
        search_query = self.request.GET.get('search', '')
        if search_query:
            queryset = queryset.filter(
                Q(title__icontains=search_query)
            )

        # Filter for non-staff users
        if not self.request.user.is_staff:
            return models.TrainingMaterial.objects.none()  # Restrict for non-staff

        return queryset.filter(created_by=self.request.user).order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        return context


class TrainingCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, CreateView):
    model = models.TrainingMaterial
    form_class = forms.TrainingMaterialForm
    template_name = 'recruitment/training_create.html'
    success_url = reverse_lazy('training_list')
    success_message = 'Training material created successfully.'

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)


class TrainingUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, UpdateView):
    model = models.TrainingMaterial
    form_class = forms.TrainingMaterialForm
    template_name = 'recruitment/training_update.html'
    success_url = reverse_lazy('training_list')
    success_message = 'Training material updated successfully.'
    slug_url_kwarg = 'slug'


class TrainingDetailView(LoginRequiredMixin, StaffRequiredMixin, DetailView):
    model = models.TrainingMaterial
    template_name = 'recruitment/training_detail.html'
    context_object_name = 'material'
    slug_url_kwarg = 'slug'

class TrainingDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
    model = models.TrainingMaterial
    template_name = 'recruitment/training_delete.html'
    success_url = reverse_lazy('training_list')
    success_message = 'Training material deleted successfully.'


# IMPORTANT: Ensure 'models' correctly refers to your Django models file
# Example: from . import models

# --- Constants ---
SCORE_PATH = 'ai_analysis_data__analysis_data__match_score'
HIGH_POTENTIAL_THRESHOLD = 75
MAX_TIME_TO_HIRE_DAYS = 90
TARGET_TIME_TO_HIRE_DAYS = 45 # Used for the template visualization


@login_required
@staff_user_required
def dashboard_view(request):

    selected_job_pk = request.GET.get('selected_job_pk')
    today = timezone.now().date()

    # --- 1. BASE QUERYSETS & GLOBAL METRICS (UNFILTERED) ---

    all_jobs_queryset = models.JobPosting.objects.all().order_by('-created_at')
    all_candidates_queryset = models.Application.objects.all()

    # Global KPI Card Metrics
    total_jobs_global = all_jobs_queryset.count()
    total_participants = models.Participants.objects.count()
    total_jobs_posted_linkedin = all_jobs_queryset.filter(linkedin_post_id__isnull=False).count()

    # Data for Job App Count Chart (always for ALL jobs)
    job_titles = [job.title for job in all_jobs_queryset]
    job_app_counts = [job.applications.count() for job in all_jobs_queryset]

    # --- 2. TIME SERIES: GLOBAL DAILY APPLICANTS ---

    # Group ALL candidates by creation date
    global_daily_applications_qs = all_candidates_queryset.annotate(
        date=TruncDate('created_at')
    ).values('date').annotate(
        count=Count('pk')
    ).order_by('date')

    global_dates = [item['date'].strftime('%Y-%m-%d') for item in global_daily_applications_qs]
    global_counts = [item['count'] for item in global_daily_applications_qs]


    # --- 3. FILTERING LOGIC: Determine the scope for scoped metrics ---

    candidate_queryset = all_candidates_queryset
    job_scope_queryset = all_jobs_queryset
    interview_queryset = models.ScheduledInterview.objects.all()

    current_job = None
    if selected_job_pk:
        # Filter all base querysets
        candidate_queryset = candidate_queryset.filter(job__pk=selected_job_pk)
        interview_queryset = interview_queryset.filter(job__pk=selected_job_pk)

        try:
            current_job = all_jobs_queryset.get(pk=selected_job_pk)
            job_scope_queryset = models.JobPosting.objects.filter(pk=selected_job_pk)
        except models.JobPosting.DoesNotExist:
            pass

    # --- 4. TIME SERIES: SCOPED DAILY APPLICANTS ---

    # Only run if a specific job is selected
    scoped_dates = []
    scoped_counts = []
    if selected_job_pk:
        scoped_daily_applications_qs = candidate_queryset.annotate(
            date=TruncDate('created_at')
        ).values('date').annotate(
            count=Count('pk')
        ).order_by('date')

        scoped_dates = [item['date'].strftime('%Y-%m-%d') for item in scoped_daily_applications_qs]
        scoped_counts = [item['count'] for item in scoped_daily_applications_qs]


    # --- 5. SCOPED CORE AGGREGATIONS (FILTERED OR ALL) ---

    total_candidates = candidate_queryset.count()

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

    # safe_match_score_cast = Cast(
    #     # 3. If the result after stripping quotes is an empty string (''), convert it to NULL.
    #     NullIf(
    #         # 2. Use Replace to remove the literal double quotes (") that might be present.
    #         Replace(
    #             # 1. Use the double-underscore path (which uses the ->> operator for the final value) 
    #             # and cast to CharField for text-based cleanup functions.
    #             Cast(SCORE_PATH, output_field=CharField()), 
    #             Value('"'), Value('') # Replace the double quote character with an empty string
    #         ),
    #         Value('') # Value to check for (empty string)
    #     ),
    #     output_field=IntegerField()               # 4. Cast the clean, non-empty string (or NULL) to an integer.
    # )

    
    # candidates_with_score_query= candidate_queryset.filter(is_resume_parsed=True).annotate(
    #     # The Coalesce handles NULL values (from missing data, non-numeric data, or NullIf) and sets them to 0.
    #     annotated_match_score=Coalesce(safe_match_score_cast, Value(0)) 
    # )



    # A. Pipeline & Volume Metrics (Scoped)
    total_active_jobs = job_scope_queryset.filter(status="ACTIVE").count()
    last_week = timezone.now() - timedelta(days=7)
    new_candidates_7days = candidate_queryset.filter(created_at__gte=last_week).count()

    open_positions_agg = job_scope_queryset.filter(status="ACTIVE").aggregate(total_open=Sum('open_positions'))
    total_open_positions = open_positions_agg['total_open'] or 0
    average_applications_result = job_scope_queryset.annotate(
        candidate_count=Count('applications', distinct=True)
    ).aggregate(avg_apps=Avg('candidate_count'))['avg_apps']
    average_applications = round(average_applications_result or 0, 2)


    # B. Efficiency & Conversion Metrics (Scoped)
    hired_candidates = candidate_queryset.filter(
        stage='Hired'
    )

    lst=[c.time_to_hire_days for c in hired_candidates]

    time_to_hire_query = hired_candidates.annotate(
        time_diff=ExpressionWrapper(
            F('join_date') - F('created_at__date'),
            output_field=fields.DurationField()
        )
    ).aggregate(avg_time_to_hire=Avg('time_diff'))

    print(time_to_hire_query)



    avg_time_to_hire_days = (
        time_to_hire_query.get('avg_time_to_hire').days
        if time_to_hire_query.get('avg_time_to_hire') else 0
    )
    print(avg_time_to_hire_days)

    applied_count = candidate_queryset.filter(stage='Applied').count()
    advanced_count = candidate_queryset.filter(stage__in=['Exam', 'Interview', 'Offer']).count()
    screening_pass_rate = round( (advanced_count / applied_count) * 100, 1 ) if applied_count > 0 else 0
    offers_extended_count = candidate_queryset.filter(stage='Offer').count()
    offers_accepted_count = candidate_queryset.filter(offer_status='Accepted').count()
    offers_accepted_rate = round( (offers_accepted_count / offers_extended_count) * 100, 1 ) if offers_extended_count > 0 else 0
    filled_positions = offers_accepted_count
    vacancy_fill_rate = round( (filled_positions / total_open_positions) * 100, 1 ) if total_open_positions > 0 else 0


    # C. Activity & Quality Metrics (Scoped)
    current_year, current_week, _ = today.isocalendar()
    meetings_scheduled_this_week = interview_queryset.filter(
        interview_date__week=current_week, interview_date__year=current_year
    ).count()
    avg_match_score_result = candidates_with_score_query.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_query.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
    total_scored_candidates = candidates_with_score_query.count()
    scored_ratio = round( (total_scored_candidates / total_candidates) * 100, 1 ) if total_candidates > 0 else 0


    # --- 6. CHART DATA PREPARATION ---

    # A. Pipeline Funnel (Scoped)
    stage_counts = candidate_queryset.values('stage').annotate(count=Count('stage'))
    stage_map = {item['stage']: item['count'] for item in stage_counts}
    candidate_stage = ['Applied', 'Exam', 'Interview', 'Offer', 'Hired']
    candidates_count = [
        stage_map.get('Applied', 0), stage_map.get('Exam', 0), stage_map.get('Interview', 0),
        stage_map.get('Offer', 0), stage_map.get('Hired',0)
    ]


    # --- 7. GAUGE CHART CALCULATION (Time-to-Hire) ---

    current_days = avg_time_to_hire_days
    rotation_percent = current_days / MAX_TIME_TO_HIRE_DAYS if MAX_TIME_TO_HIRE_DAYS > 0 else 0
    rotation_degrees = rotation_percent * 180
    rotation_degrees_final = round(min(rotation_degrees, 180), 1) # Ensure max 180 degrees

    #
    hiring_source_counts = candidate_queryset.values('hiring_source').annotate(count=Count('stage'))
    source_map= {item['hiring_source']: item['count'] for item in hiring_source_counts}
    candidates_count_in_each_source = [
        source_map.get('Public', 0), source_map.get('Internal', 0), source_map.get('Agency', 0),

    ]
    all_hiring_sources=["Public", "Internal", "Agency"]


    # --- 8. CONTEXT RETURN ---

    context = {
        # Global KPIs
        'total_jobs_global': total_jobs_global,
        'total_participants': total_participants,
        'total_jobs_posted_linkedin': total_jobs_posted_linkedin,

        # Scoped KPIs
        'total_active_jobs': total_active_jobs,
        'total_candidates': total_candidates,
        'new_candidates_7days': new_candidates_7days,
        'total_open_positions': total_open_positions,
        'average_applications': average_applications,
        'avg_time_to_hire_days': avg_time_to_hire_days,
        'screening_pass_rate': screening_pass_rate,
        'offers_accepted_rate': offers_accepted_rate,
        'vacancy_fill_rate': vacancy_fill_rate,
        'meetings_scheduled_this_week': meetings_scheduled_this_week,
        'avg_match_score': avg_match_score,
        'high_potential_count': high_potential_count,
        'high_potential_ratio': high_potential_ratio,
        'scored_ratio': scored_ratio,

        # Chart Data
        'candidate_stage': json.dumps(candidate_stage),
        'candidates_count': json.dumps(candidates_count),
        'job_titles': json.dumps(job_titles),
        'job_app_counts': json.dumps(job_app_counts),
        # 'source_volume_chart_data' is intentionally REMOVED

        # Time Series Data
        'global_dates': json.dumps(global_dates),
        'global_counts': json.dumps(global_counts),
        'scoped_dates': json.dumps(scoped_dates),
        'scoped_counts': json.dumps(scoped_counts),
        'is_job_scoped': bool(selected_job_pk),

        # Gauge Data
        'gauge_max_days': MAX_TIME_TO_HIRE_DAYS,
        'gauge_target_days': TARGET_TIME_TO_HIRE_DAYS,
        'gauge_rotation_degrees': rotation_degrees_final,

        # UI Control
        'jobs': all_jobs_queryset,
        'current_job_id': selected_job_pk,
        'current_job': current_job,


        'candidates_count_in_each_source': json.dumps(candidates_count_in_each_source),
        'all_hiring_sources': json.dumps(all_hiring_sources),
    }

    return render(request, 'recruitment/dashboard.html', context)


@login_required
@staff_user_required
def candidate_offer_view(request, slug):
    """View for candidates in the Offer stage"""
    job = get_object_or_404(models.JobPosting, slug=slug)

    # Filter candidates for this specific job and stage
    candidates = job.offer_candidates

    # Handle search
    search_query = request.GET.get('search', '')
    if search_query:
        candidates = candidates.filter(
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(email__icontains=search_query) |
            Q(phone__icontains=search_query)
        )

    candidates = candidates.order_by('-created_at')

    context = {
        'job': job,
        'candidates': candidates,
        'search_query': search_query,
        'current_stage': 'Offer',
    }
    return render(request, 'recruitment/candidate_offer_view.html', context)


@login_required
@staff_user_required
def candidate_hired_view(request, slug):
    """View for hired candidates"""
    job = get_object_or_404(models.JobPosting, slug=slug)

    # Filter candidates with offer_status = 'Accepted'
    candidates = job.hired_candidates

    # Handle search
    search_query = request.GET.get('search', '')
    if search_query:
        candidates = candidates.filter(
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(email__icontains=search_query) |
            Q(phone__icontains=search_query)
        )

    candidates = candidates.order_by('-created_at')

    context = {
        'job': job,
        'candidates': candidates,
        'search_query': search_query,
        'current_stage': 'Hired',
    }
    return render(request, 'recruitment/candidate_hired_view.html', context)


@login_required
@staff_user_required
def update_candidate_status(request, job_slug, candidate_slug, stage_type, status):
    """Handle exam/interview/offer status updates"""
    from django.utils import timezone

    job = get_object_or_404(models.JobPosting, slug=job_slug)
    candidate = get_object_or_404(models.Application, slug=candidate_slug, job=job)

    if request.method == "POST":
        if stage_type == 'exam':
            status = request.POST.get("exam_status")
            score = request.POST.get("exam_score")
            candidate.exam_status = status
            candidate.exam_score = score
            candidate.exam_date = timezone.now()
            candidate.save(update_fields=['exam_status','exam_score', 'exam_date'])
            return render(request,'recruitment/partials/exam-results.html',{'candidate':candidate,'job':job})
        elif stage_type == 'interview':
            candidate.interview_status = status
            candidate.interview_date = timezone.now()
            candidate.save(update_fields=['interview_status', 'interview_date'])
            return render(request,'recruitment/partials/interview-results.html',{'candidate':candidate,'job':job})
        elif stage_type == 'offer':
            candidate.offer_status = status
            candidate.offer_date = timezone.now()
            candidate.save(update_fields=['offer_status', 'offer_date'])
            return render(request,'recruitment/partials/offer-results.html',{'candidate':candidate,'job':job})
        return redirect('candidate_detail', candidate.slug)
    else:
        if stage_type == 'exam':
            return render(request,"includes/candidate_update_exam_form.html",{'candidate':candidate,'job':job})
        elif stage_type == 'interview':
            return render(request,"includes/candidate_update_interview_form.html",{'candidate':candidate,'job':job})
        elif stage_type == 'offer':
            return render(request,"includes/candidate_update_offer_form.html",{'candidate':candidate,'job':job})


# Stage configuration for CSV export
STAGE_CONFIG = {
    'screening': {
        'filter': {'stage': 'Applied'},
        'fields': ['name', 'email', 'phone', 'created_at', 'stage', 'ai_score', 'years_experience', 'screening_rating', 'professional_category', 'top_skills', 'strengths', 'weaknesses'],
        'headers': ['Name', 'Email', 'Phone', 'Application Date', 'Screening Status', 'Match Score', 'Years Experience', 'Screening Rating', 'Professional Category', 'Top 3 Skills', 'Strengths', 'Weaknesses']
    },
    'exam': {
        'filter': {'stage': 'Exam'},
        'fields': ['name', 'email', 'phone', 'created_at', 'exam_status', 'exam_date', 'ai_score', 'years_experience', 'screening_rating'],
        'headers': ['Name', 'Email', 'Phone', 'Application Date', 'Exam Status', 'Exam Date', 'Match Score', 'Years Experience', 'Screening Rating']
    },
    'interview': {
        'filter': {'stage': 'Interview'},
        'fields': ['name', 'email', 'phone', 'created_at', 'interview_status', 'interview_date', 'ai_score', 'years_experience', 'professional_category', 'top_skills'],
        'headers': ['Name', 'Email', 'Phone', 'Application Date', 'Interview Status', 'Interview Date', 'Match Score', 'Years Experience', 'Professional Category', 'Top 3 Skills']
    },
    'offer': {
        'filter': {'stage': 'Offer'},
        'fields': ['name', 'email', 'phone', 'created_at', 'offer_status', 'offer_date', 'ai_score', 'years_experience', 'professional_category'],
        'headers': ['Name', 'Email', 'Phone', 'Application Date', 'Offer Status', 'Offer Date', 'Match Score', 'Years Experience', 'Professional Category']
    },
    'hired': {
        'filter': {'offer_status': 'Accepted'},
        'fields': ['name', 'email', 'phone', 'created_at', 'offer_date', 'ai_score', 'years_experience', 'professional_category', 'join_date'],
        'headers': ['Name', 'Email', 'Phone', 'Application Date', 'Hire Date', 'Match Score', 'Years Experience', 'Professional Category', 'Join Date']
    }
}


@login_required
@staff_user_required
def export_candidates_csv(request, job_slug, stage):
    """Export candidates for a specific stage as CSV"""
    job = get_object_or_404(models.JobPosting, slug=job_slug)

    # Validate stage
    if stage not in STAGE_CONFIG:
        messages.error(request, "Invalid stage specified for export.")
        return redirect('job_detail', job.slug)

    config = STAGE_CONFIG[stage]

    # Filter candidates based on stage
    if stage == 'hired':
        candidates = job.applications.filter(**config['filter'])
    else:
        candidates = job.applications.filter(**config['filter'])

    # Handle search if provided
    search_query = request.GET.get('search', '')
    if search_query:
        candidates = candidates.filter(
            Q(first_name__icontains=search_query) |
            Q(last_name__icontains=search_query) |
            Q(email__icontains=search_query) |
            Q(phone__icontains=search_query)
        )

    candidates = candidates.order_by('-created_at')

    # Create CSV response
    response = HttpResponse(content_type='text/csv')
    filename = f"{slugify(job.title)}_{stage}_{datetime.now().strftime('%Y-%m-%d')}.csv"
    response['Content-Disposition'] = f'attachment; filename="{filename}"'

    # Write UTF-8 BOM for Excel compatibility
    response.write('\ufeff')

    writer = csv.writer(response)

    # Write headers
    headers = config['headers'].copy()
    headers.extend(['Job Title', 'Department'])
    writer.writerow(headers)

    # Write candidate data
    for candidate in candidates:
        row = []

        # Extract data based on stage configuration
        for field in config['fields']:
            if field == 'name':
                row.append(candidate.name)
            elif field == 'email':
                row.append(candidate.email)
            elif field == 'phone':
                row.append(candidate.phone)
            elif field == 'created_at':
                row.append(candidate.created_at.strftime('%Y-%m-%d %H:%M') if candidate.created_at else '')
            elif field == 'stage':
                row.append(candidate.stage or '')
            elif field == 'exam_status':
                row.append(candidate.exam_status or '')
            elif field == 'exam_date':
                row.append(candidate.exam_date.strftime('%Y-%m-%d %H:%M') if candidate.exam_date else '')
            elif field == 'interview_status':
                row.append(candidate.interview_status or '')
            elif field == 'interview_date':
                row.append(candidate.interview_date.strftime('%Y-%m-%d %H:%M') if candidate.interview_date else '')
            elif field == 'offer_status':
                row.append(candidate.offer_status or '')
            elif field == 'offer_date':
                row.append(candidate.offer_date.strftime('%Y-%m-%d %H:%M') if candidate.offer_date else '')
            elif field == 'ai_score':
                # Extract AI score using model property
                try:
                    score = candidate.match_score
                    row.append(f"{score}%" if score else '')
                except:
                    row.append('')
            elif field == 'years_experience':
                # Extract years of experience using model property
                try:
                    years = candidate.years_of_experience
                    row.append(f"{years}" if years else '')
                except:
                    row.append('')
            elif field == 'screening_rating':
                # Extract screening rating using model property
                try:
                    rating = candidate.screening_stage_rating
                    row.append(rating if rating else '')
                except:
                    row.append('')
            elif field == 'professional_category':
                # Extract professional category using model property
                try:
                    category = candidate.professional_category
                    row.append(category if category else '')
                except:
                    row.append('')
            elif field == 'top_skills':
                # Extract top 3 skills using model property
                try:
                    skills = candidate.top_3_keywords
                    row.append(', '.join(skills) if skills else '')
                except:
                    row.append('')
            elif field == 'strengths':
                # Extract strengths using model property
                try:
                    strengths = candidate.strengths
                    row.append(strengths if strengths else '')
                except:
                    row.append('')
            elif field == 'weaknesses':
                # Extract weaknesses using model property
                try:
                    weaknesses = candidate.weaknesses
                    row.append(weaknesses if weaknesses else '')
                except:
                    row.append('')
            elif field == 'join_date':
                row.append(candidate.join_date.strftime('%Y-%m-%d') if candidate.join_date else '')
            else:
                row.append(getattr(candidate, field, ''))

        # Add job information
        row.extend([job.title, job.department or ''])

        writer.writerow(row)

    return response


# Removed incorrect
# The job_detail view is handled by function-based view in recruitment.views


@login_required
@staff_user_required
def sync_hired_candidates(request, job_slug):
    """Sync hired candidates to external sources using Django-Q"""
    from django_q.tasks import async_task
    from .tasks import sync_hired_candidates_task

    if request.method == 'POST':
        job = get_object_or_404(models.JobPosting, slug=job_slug)

        try:
            # Enqueue sync task to Django-Q for background processing
            task_id = async_task(
                sync_hired_candidates_task,
                job_slug,
                group=f"sync_job_{job_slug}",
                timeout=300  # 5 minutes timeout
            )
            print("task_id",task_id)
            # Return immediate response with task ID for tracking
            return JsonResponse({
                'status': 'queued',
                'message': 'Sync task has been queued for background processing',
                'task_id': task_id
            })

        except Exception as e:
            return JsonResponse({
                'status': 'error',
                'message': f'Failed to queue sync task: {str(e)}'
            }, status=500)

    # For GET requests, return error
    return JsonResponse({
        'status': 'error',
        'message': 'Only POST requests are allowed'
    }, status=405)


@login_required
@staff_user_required
def test_source_connection(request, source_id):
    """Test connection to an external source"""
    from .candidate_sync_service import CandidateSyncService

    if request.method == 'POST':
        source = get_object_or_404(models.Source, id=source_id)

        try:
            # Initialize sync service
            sync_service = CandidateSyncService()

            # Test connection
            result = sync_service.test_source_connection(source)

            # Return JSON response
            return JsonResponse({
                'status': 'success',
                'result': result
            })

        except Exception as e:
            return JsonResponse({
                'status': 'error',
                'message': f'Connection test failed: {str(e)}'
            }, status=500)

    # For GET requests, return error
    return JsonResponse({
        'status': 'error',
        'message': 'Only POST requests are allowed'
    }, status=405)


@login_required
@staff_user_required
def sync_task_status(request, task_id):
    """Check the status of a sync task"""
    from django_q.models import Task

    try:
        # Get the task from Django-Q
        task = Task.objects.get(pk=task_id)
        print("task",task)

        # Determine status based on task state
        if task.success:
            status = 'completed'
            message = 'Sync completed successfully'
            result = task.result
        elif task.stopped:
            status = 'failed'
            message = 'Sync task failed or was stopped'
            result = task.result
        elif task.started:
            status = 'running'
            message = 'Sync is currently running'
            result = None
        else:
            status = 'pending'
            message = 'Sync task is queued and waiting to start'
            result = None
        print("result",result)
        return JsonResponse({
            'status': status,
            'message': message,
            'result': result,
            'task_id': task_id,
            'started': task.started,
            'stopped': task.stopped,
            'success': task.success
        })

    except Task.DoesNotExist:
        return JsonResponse({
            'status': 'error',
            'message': 'Task not found'
        }, status=404)

    except Exception as e:
        return JsonResponse({
            'status': 'error',
            'message': f'Failed to check task status: {str(e)}'
        }, status=500)


@login_required
@staff_user_required
def sync_history(request, job_slug=None):
    """View sync history and logs"""
    from .models import IntegrationLog
    from django_q.models import Task

    # Get sync logs
    if job_slug:
        # Filter for specific job
        job = get_object_or_404(models.JobPosting, slug=job_slug)
        logs = IntegrationLog.objects.filter(
            action=IntegrationLog.ActionChoices.SYNC,
            request_data__job_slug=job_slug
        ).order_by('-created_at')
    else:
        # Get all sync logs
        logs = IntegrationLog.objects.filter(
            action=IntegrationLog.ActionChoices.SYNC
        ).order_by('-created_at')

    # Get recent sync tasks
    recent_tasks = Task.objects.filter(
        group__startswith='sync_job_'
    ).order_by('-started')[:20]

    context = {
        'logs': logs,
        'recent_tasks': recent_tasks,
        'job': job if job_slug else None,
    }

    return render(request, 'recruitment/sync_history.html', context)


#participants views
class ParticipantsListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
    model = models.Participants
    template_name = 'participants/participants_list.html'
    context_object_name = 'participants'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()

        # Handle search
        search_query = self.request.GET.get('search', '')
        if search_query:
            queryset = queryset.filter(
                Q(name__icontains=search_query) |
                Q(email__icontains=search_query) |
                Q(phone__icontains=search_query) |
                Q(designation__icontains=search_query)
            )

        # Filter for non-staff users
        if not self.request.user.is_staff:
            return models.Participants.objects.none()  # Restrict for non-staff

        return queryset.order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        return context
class ParticipantsDetailView(LoginRequiredMixin, StaffRequiredMixin, DetailView):
    model = models.Participants
    template_name = 'participants/participants_detail.html'
    context_object_name = 'participant'
    slug_url_kwarg = 'slug'

class ParticipantsCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, CreateView):
    model = models.Participants
    form_class = forms.ParticipantsForm
    template_name = 'participants/participants_create.html'
    success_url = reverse_lazy('job_list')
    success_message = 'Participant created successfully.'

    # def get_initial(self):
    #     initial = super().get_initial()
    #     if 'slug' in self.kwargs:
    #         job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
    #         initial['jobs'] = [job]
    #     return initial



class ParticipantsUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, UpdateView):
    model = models.Participants
    form_class = forms.ParticipantsForm
    template_name = 'participants/participants_create.html'
    success_url = reverse_lazy('job_list')
    success_message = 'Participant updated successfully.'
    slug_url_kwarg = 'slug'

class ParticipantsDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
    model = models.Participants

    success_url = reverse_lazy('participants_list') # Redirect to the participants list after success
    success_message = 'Participant deleted successfully.'
    slug_url_kwarg = 'slug'
