from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework_simplejwt.tokens import RefreshToken

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

User = get_user_model()


class CandidateAssignmentFilteringTests(APITestCase):
    def setUp(self):
        # Create user
        self.user = User.objects.create_user(
            username="testadmin",
            email="testuser@ta-ats.local",
            password="testpassword",
            first_name="Test",
            last_name="User"
        )
        self.user.role = "ADMIN"
        self.user.is_superuser = True
        self.user.is_staff = True
        self.user.save()

        # Generate JWT and apply to client
        token = RefreshToken.for_user(self.user)
        self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token.access_token}")

        # Create JobDescription
        self.job = JobDescription.objects.create(
            title="Next.js Developer",
            location="Remote",
            work_details="Work details...",
            status="Published",
            created_by=self.user,
        )

        # Create Candidates
        self.candidate1 = Candidate.objects.create(
            first_name="Alice",
            last_name="Smith",
            email="alice@example.com",
            phone_number="1234567890",
        )
        self.candidate2 = Candidate.objects.create(
            first_name="Bob",
            last_name="Jones",
            email="bob@example.com",
            phone_number="9876543210",
        )

    def test_exclude_job_filtering(self):
        # Initial candidates list call (no exclude_job param)
        url = reverse("candidates:candidate-list-create")
        response = self.client.get(url, {"page": 1})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # Verify both candidates are present
        emails = [item["email"] for item in response.data["data"]["results"]]
        self.assertIn("alice@example.com", emails)
        self.assertIn("bob@example.com", emails)

        # Now assign candidate1 to the job
        application = JobApplication.objects.create(
            candidate=self.candidate1,
            job=self.job
        )

        # Fetch candidates with exclude_job filter
        response = self.client.get(url, {"page": 1, "exclude_job": self.job.id})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        emails = [item["email"] for item in response.data["data"]["results"]]
        # candidate1 should be excluded because she is assigned to the job
        self.assertNotIn("alice@example.com", emails)
        self.assertIn("bob@example.com", emails)

        # Fetch candidates without exclude_job filter
        response = self.client.get(url, {"page": 1})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        emails = [item["email"] for item in response.data["data"]["results"]]
        self.assertIn("alice@example.com", emails)
        self.assertIn("bob@example.com", emails)

        # Delete the application (unassign candidate1)
        application.delete()

        # Fetch candidates with exclude_job filter again
        response = self.client.get(url, {"page": 1, "exclude_job": self.job.id})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        emails = [item["email"] for item in response.data["data"]["results"]]
        # candidate1 should now be back
        self.assertIn("alice@example.com", emails)
        self.assertIn("bob@example.com", emails)

    def test_candidate_get_for_user(self):
        # Create a new user with CANDIDATE role
        candidate_user = User.objects.create_user(
            username="candidate_test@example.com",
            email="candidate_test@example.com",
            password="testpassword",
            first_name="Candidate",
            last_name="Test"
        )
        candidate_user.role = "CANDIDATE"
        candidate_user.save()

        # get_for_user should auto-create the candidate profile since they are a CANDIDATE user
        profile = Candidate.get_for_user(candidate_user)
        self.assertIsNotNone(profile)
        self.assertEqual(profile.user, candidate_user)
        self.assertEqual(profile.email, candidate_user.email)

        # Linking fallback: create a candidate first with no user
        unlinked_candidate = Candidate.objects.create(
            first_name="Unlinked",
            last_name="User",
            email="unlinked@example.com",
            phone_number="1234567890"
        )
        # Create matching user
        unlinked_user = User.objects.create_user(
            username="unlinked@example.com",
            email="unlinked@example.com",
            password="testpassword"
        )
        # get_for_user should find and link the existing candidate
        linked_profile = Candidate.get_for_user(unlinked_user)
        self.assertEqual(linked_profile.id, unlinked_candidate.id)
        self.assertEqual(linked_profile.user, unlinked_user)

