from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import JobOffer, JobApplication, JobOfferSubscriber
from .serializers import (
    JobOfferSerializer,
    JobOfferAdminSerializer,
    JobApplicationSerializer,
    JobApplicationAdminSerializer,
)
from .emails import (
    send_application_confirmation,
    send_application_status_email,
    send_new_offer_notification,
    get_unsubscribe_token,
)


class JobOfferViewSet(viewsets.ModelViewSet):
    """
    Offres d'emploi.
    - GET /offers/public/ : liste des offres actives (public).
    - CRUD /offers/ : admin uniquement (create = formulaire admin avec titre, poste, deadline, image/pdf).
    """
    queryset = JobOffer.objects.all()

    def get_serializer_class(self):
        if self.action in ["create", "update", "partial_update"]:
            return JobOfferAdminSerializer
        return JobOfferSerializer

    def get_permissions(self):
        if self.action == "list_public":
            return [permissions.AllowAny()]
        return [permissions.IsAdminUser()]

    def perform_create(self, serializer):
        offer = serializer.save()
        if offer.is_active:
            send_new_offer_notification(offer)

    def perform_update(self, serializer):
        old_active = serializer.instance.is_active if serializer.instance else False
        offer = serializer.save()
        if offer.is_active and not old_active:
            send_new_offer_notification(offer)

    @action(detail=False, methods=["get"], url_path="public")
    def list_public(self, request):
        """Liste des offres actives pour la page emplois publique."""
        qs = JobOffer.objects.filter(is_active=True).order_by("-created_at")
        serializer = JobOfferSerializer(qs, many=True)
        return Response(serializer.data)


class JobApplicationViewSet(viewsets.ModelViewSet):
    """
    Candidatures.
    - POST /applications/ : dépôt de candidature (public) → email confirmation + numéro de dépôt.
    - GET/PATCH /applications/ : admin (liste, détail, modifier statut) → email selon statut.
    """
    queryset = JobApplication.objects.all().select_related("job_offer")

    def get_serializer_class(self):
        if self.action in ["create"]:
            return JobApplicationSerializer
        return JobApplicationAdminSerializer

    def get_permissions(self):
        if self.action == "create":
            return [permissions.AllowAny()]
        return [permissions.IsAdminUser()]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        application = serializer.save()
        send_application_confirmation(application)
        return Response(
            JobApplicationAdminSerializer(application).data,
            status=status.HTTP_201_CREATED,
        )

    def perform_update(self, serializer):
        old_instance = self.get_object()
        old_status = old_instance.status
        application = serializer.save()
        if application.status != old_status:
            send_application_status_email(application, old_status=old_status)


def unsign_email(token):
    """Désigne le token pour récupérer l'email. Retourne None si invalide."""
    from django.core.signing import Signer, BadSignature
    from urllib.parse import unquote
    try:
        raw = unquote(token)
        return Signer().unsign(raw)
    except (BadSignature, TypeError, ValueError):
        return None


class JobUnsubscribeView(APIView):
    """Désabonnement aux notifications offres (lien dans l'email). GET ?token=..."""
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        token = request.query_params.get("token", "")
        email = unsign_email(token)
        if not email:
            return Response(
                {"success": False, "message": "Lien invalide ou expiré."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        from django.contrib.auth import get_user_model
        User = get_user_model()
        if User.objects.filter(email__iexact=email).exists():
            User.objects.filter(email__iexact=email).update(receive_job_offers_notifications=False)
        for s in JobOfferSubscriber.objects.filter(email__iexact=email):
            s.subscribed = False
            s.save()
        return Response({"success": True, "message": "Vous ne recevrez plus les notifications d'offres par email."})


class JobSubscribeView(APIView):
    """Abonnement aux notifications offres (candidats / visiteurs). POST { email }"""
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        email = (request.data.get("email") or "").strip()
        if not email or "@" not in email:
            return Response(
                {"success": False, "message": "Email invalide."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        sub = JobOfferSubscriber.objects.filter(email__iexact=email).first()
        if sub:
            sub.subscribed = True
            sub.save()
        else:
            JobOfferSubscriber.objects.create(email=email, subscribed=True)
        return Response({"success": True, "message": "Vous êtes abonné aux nouvelles offres."})
