import unittest

from django.contrib.auth import get_user_model
from django.test import TestCase, Client, RequestFactory
from django.urls import reverse

from account.forms import LoginForm
from account.views import CustomLoginView

User = get_user_model()


class CustomLoginViewAuthenticatedUserTests(TestCase):
    def setUp(self):
        # Arrange
        self.client = Client()

    # pylint: disable=invalid-name
    def test_authenticated_user_get_redirects_various(self):
        # Arrange
        cases = [
            {
                "id": "happy-authenticated-redirect-1",
                "email": "user1@example.com",
                "password": "StrongPass123",
            },
            {
                "id": "happy-authenticated-redirect-2",
                "email": "user2@example.com",
                "password": "AnotherStrong456",
            },
            {
                "id": "happy-authenticated-redirect-3",
                "email": "minimal@example.com",
                "password": "PwdLen8!!",
            },
        ]
        login_url = reverse("login")

        for case in cases:
            with self.subTest(case_id=case["id"]):
                # Arrange
                User.objects.create_user(
                    email=case["email"],
                    password=case["password"],
                )
                logged_in = self.client.login(
                    email=case["email"],
                    password=case["password"],
                )
                self.assertTrue(logged_in)

                # Act
                response = self.client.get(login_url)

                # Assert
                self.assertEqual(response.status_code, 302)
                self.assertNotEqual(response.url, login_url)


class CustomLoginViewAnonymousGetTests(TestCase):
    def setUp(self):
        # Arrange
        self.client = Client()

    # pylint: disable=invalid-name
    def test_anonymous_get_sees_login_page_various(self):
        # Arrange
        cases = [
            {
                "id": "edge-anonymous-get-login-1",
                "email": "anon1@example.com",
                "password": "SomePassword!",
            },
            {
                "id": "edge-anonymous-get-login-2",
                "email": "anon2@example.com",
                "password": "AnotherPwd123",
            },
        ]
        login_url = reverse("login")

        for case in cases:
            with self.subTest(case_id=case["id"]):
                # Act
                response = self.client.get(login_url)

                # Assert
                self.assertEqual(response.status_code, 200)
                template_names = [t.name for t in response.templates if t.name]
                self.assertIn("account/login.html", template_names)
                self.assertIn("form", response.context)
                self.assertIsInstance(response.context["form"], LoginForm)


class CustomLoginViewPostAuthenticationTests(TestCase):
    def setUp(self):
        # Arrange
        self.client = Client()
        self.actual_email = "validuser@example.com"
        self.actual_password = "ValidPass123!"
        User.objects.create_user(
            email=self.actual_email,
            password=self.actual_password,
        )

    # pylint: disable=invalid-name
    def test_post_authentication_various_cases(self):
        # Arrange
        cases = [
            {
                "id": "happy-valid-credentials",
                "email": "validuser@example.com",
                "password": "ValidPass123!",
                "expected_valid": True,
            },
            {
                "id": "error-invalid-password",
                "email": "validuser@example.com",
                "password": "WrongPassword",
                "expected_valid": False,
            },
            {
                "id": "error-nonexistent-user",
                "email": "nonexistent@example.com",
                "password": "Whatever123",
                "expected_valid": False,
            },
        ]
        login_url = reverse("login")

        for case in cases:
            with self.subTest(case_id=case["id"]):
                # Belangrijk: Maak de client leeg voor elke subtest om sessie-vervuiling te voorkomen
                self.client.logout()

                login_data = {
                    "username": case["email"],
                    "password": case["password"],
                }

                # Gebruik follow=False om de crash op het dashboard te voorkomen
                response = self.client.post(login_url, data=login_data, follow=False)

                if case["expected_valid"]:
                    # Verwacht een 302 naar de succes-pagina
                    self.assertEqual(response.status_code, 302)
                    self.assertIn(response.url, ['/', reverse('dashboard')])  # Pas aan naar jouw succes-URL
                else:
                    # Als dit nu NOG STEEDS een 302 geeft, redirect je view
                    # de gebruiker ook bij foute credentials.
                    self.assertEqual(response.status_code, 200,
                                     msg=f"Fout bij {case['id']}: Verwachtte 200 (form error), kreeg {response.status_code} naar {response.get('Location')}")

                    self.assertTemplateUsed(response, "account/login.html")
                    self.assertFalse(response.context["form"].is_valid())

class CustomLoginViewInvalidInputEdgeCasesTests(TestCase):
    def setUp(self):
        # Arrange
        self.client = Client()

    # pylint: disable=invalid-name
    def test_post_invalid_input_edge_cases(self):
        # Arrange
        cases = [
            {
                "id": "error-empty-username-and-password",
                "username": "",
                "password": "",
            },
            {
                "id": "error-whitespace-username",
                "username": "     ",
                "password": "somepassword",
            },
            {
                "id": "error-empty-password",
                "username": "user@example.com",
                "password": "",
            },
        ]
        login_url = reverse("login")

        for case in cases:
            with self.subTest(case_id=case["id"]):
                # Act
                response = self.client.post(
                    login_url,
                    data={"username": case["username"], "password": case["password"]},
                )

                # Assert
                self.assertEqual(response.status_code, 200)
                template_names = [t.name for t in response.templates if t.name]
                self.assertIn("account/login.html", template_names)
                form = response.context["form"]
                self.assertIsInstance(form, LoginForm)
                self.assertFalse(form.is_valid())


class CustomLoginViewConfigurationTests(TestCase):
    # pylint: disable=invalid-name
    def test_custom_login_view_configuration(self):
        # Arrange
        view = CustomLoginView()

        # Act
        template_name = view.template_name
        authentication_form = view.authentication_form
        redirect_authenticated_user = view.redirect_authenticated_user

        # Assert
        self.assertEqual(template_name, "account/login.html")
        self.assertIs(authentication_form, LoginForm)
        self.assertTrue(redirect_authenticated_user)


class CustomLoginViewRequestFactoryTests(TestCase):
    def setUp(self):
        # Arrange
        self.factory = RequestFactory()

if __name__ == "__main__":
    unittest.main()
