"""Public (unauthenticated) careers endpoints.

Exposes only Published job descriptions, through a trimmed serializer that hides
internal fields (created_by, assigned_recruiters, rank_weights, postings, …).
"""

from rest_framework import serializers
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.permissions import AllowAny

from .models import JobDescription
from apps.pipeline.models import JobApplication
from apps.candidates.models import Candidate


class PublicJobSerializer(serializers.ModelSerializer):
    client_name = serializers.CharField(source="client.name", default=None, read_only=True)
    applicants_count = serializers.SerializerMethodField()
    is_applied = serializers.SerializerMethodField()
    applied_at = serializers.SerializerMethodField()

    class Meta:
        model = JobDescription
        fields = [
            "id", "public_id", "title", "department", "location",
            "experience_band", "ctc_band", "notice_period", "shift",
            "must_have_skills", "good_to_have_skills", "qualifications",
            "working_days", "num_positions", "certification",
            "work_details", "client_name", "created_at", "applicants_count",
            "is_applied", "applied_at",
        ]

    def get_applicants_count(self, obj):
        try:
            return obj.applications.count()
        except Exception:
            return 0
            
    def get_is_applied(self, obj):
        request = self.context.get("request")
        if not request or not request.user or not request.user.is_authenticated:
            return False
        candidate = Candidate.get_for_user(request.user)
        if not candidate:
            return False
        return JobApplication.objects.filter(candidate=candidate, job=obj).exists()
        
    def get_applied_at(self, obj):
        request = self.context.get("request")
        if not request or not request.user or not request.user.is_authenticated:
            return None
        candidate = Candidate.get_for_user(request.user)
        if not candidate:
            return None
        app = JobApplication.objects.filter(candidate=candidate, job=obj).first()
        return app.created_at.isoformat() if app else None


class PublicJobListView(ListAPIView):
    """GET /api/v1/public/jobs/ — all Published JDs (search by ?q=)."""

    permission_classes = [AllowAny]
    serializer_class = PublicJobSerializer

    def get_queryset(self):
        qs = JobDescription.objects.filter(status="Published").select_related("client").order_by("-created_at")
        q = self.request.query_params.get("q")
        if q:
            from django.db.models import Q
            qs = qs.filter(
                Q(title__icontains=q) | Q(location__icontains=q)
                | Q(department__icontains=q) | Q(must_have_skills__icontains=q)
            )
        return qs


class PublicJobDetailView(RetrieveAPIView):
    """GET /api/v1/public/jobs/<public_id>/ — one Published JD.

    Looks up by the unguessable UUID `public_id`. Falls back to the integer id
    so old links (/careers/jobs/595) keep working.
    """

    permission_classes = [AllowAny]
    serializer_class = PublicJobSerializer
    queryset = JobDescription.objects.filter(status="Published").select_related("client")

    def get_object(self):
        import uuid
        from django.http import Http404
        from core.crypto import short_decode_id
        pk = str(self.kwargs.get("pk"))
        obj = None
        try:
            uuid.UUID(pk)
            obj = JobDescription.objects.filter(public_id=pk).select_related("client").first()
        except (ValueError, TypeError):
            pass

        if not obj and pk.isdigit():
            obj = JobDescription.objects.filter(id=int(pk)).select_related("client").first()

        if not obj:
            decoded = short_decode_id(pk)
            if decoded is not None:
                obj = JobDescription.objects.filter(id=decoded).select_related("client").first()

        if not obj:
            raise Http404("Job not found.")
        return obj
