import unittest

from django import forms
from django.contrib.auth import get_user_model
from django.test import TestCase

from account.forms import RegistrationForm

User = get_user_model()


class TestRegistrationFormValidation(TestCase):
    # pylint: disable=invalid-name
    def test_registration_form_validation_various_cases(self):
        # Arrange
        cases = [
            # Happy paths
            {
                "id": "happy-basic-valid",
                "data": {
                    "email": "user@example.com",
                    "company_name": "Mijn Bouwbedrijf B.V.",
                    "password1": "strongPass123",
                    "password2": "strongPass123",
                },
                "expected_valid": True,
            },
            {
                "id": "happy-another-valid",
                "data": {
                    "email": "another.user@bedrijf.nl",
                    "company_name": "Ashlar Systems",
                    "password1": "anotherStrongPass456",
                    "password2": "anotherStrongPass456",
                },
                "expected_valid": True,
            },
            {
                "id": "happy-min-companyname-length",
                "data": {
                    "email": "short@co.nl",
                    "company_name": "A",
                    "password1": "passwordLen8",
                    "password2": "passwordLen8",
                },
                "expected_valid": True,
            },
            # Error: password mismatch
            {
                "id": "error-password-mismatch",
                "data": {
                    "email": "mismatch@bedrijf.nl",
                    "company_name": "Mismatch Company",
                    "password1": "password123",
                    "password2": "different123",
                },
                "expected_valid": False,
            },
            # Error: missing company_name
            {
                "id": "error-missing-company-name",
                "data": {
                    "email": "no-company@bedrijf.nl",
                    "company_name": "",
                    "password1": "password123",
                    "password2": "password123",
                },
                "expected_valid": False,
            },
            # Error: invalid email
            {
                "id": "error-invalid-email-format",
                "data": {
                    "email": "not-an-email",
                    "company_name": "Bad Email Company",
                    "password1": "password123",
                    "password2": "password123",
                },
                "expected_valid": False,
            },
        ]

        # Act
        for case in cases:
            with self.subTest(case_id=case["id"]):
                form = RegistrationForm(data=case["data"])

                # Assert
                self.assertIs(form.is_valid(), case["expected_valid"])
                if case["expected_valid"]:
                    self.assertNotIn("email", form.errors)
                    self.assertNotIn("company_name", form.errors)
                    self.assertNotIn("password1", form.errors)
                    self.assertNotIn("password2", form.errors)
                else:
                    self.assertTrue(form.errors)


class TestRegistrationFormMetaAndFields(TestCase):
    # pylint: disable=invalid-name
    def test_registration_form_meta_uses_user_and_email_field(self):
        # Arrange
        form = RegistrationForm()

        # Act
        meta_model = form._meta.model
        meta_fields = form._meta.fields

        # Assert
        self.assertIs(meta_model, User)
        self.assertEqual(meta_fields, ("email",))

    # pylint: disable=invalid-name
    def test_registration_form_applies_tailwind_classes_to_all_fields(self):
        # Arrange
        form = RegistrationForm()

        # Act
        widget_classes = {
            name: field.widget.attrs.get("class", "")
            for name, field in form.fields.items()
        }

        # Assert
        tailwind_snippet = "block w-full appearance-none rounded-md border"
        self.assertTrue(widget_classes, "Form should have fields")
        for field_name, classes in widget_classes.items():
            with self.subTest(field=field_name):
                self.assertIn(tailwind_snippet, classes)


    # pylint: disable=invalid-name
    def test_registration_form_sets_password1_help_text(self):
        # Arrange
        form = RegistrationForm()

        # Act
        help_text = form.fields["password1"].help_text

        # Assert
        self.assertEqual(help_text, "Gebruik minimaal 8 tekens.")

    # pylint: disable=invalid-name
    def test_registration_form_required_fields(self):
        # Arrange
        base_data = {
            "email": "required@bedrijf.nl",
            "company_name": "Required Co",
            "password1": "password123",
            "password2": "password123",
        }
        cases = [
            {
                "id": "missing-email",
                "missing_field": "email",
            },
            {
                "id": "missing-company-name",
                "missing_field": "company_name",
            },
            {
                "id": "missing-password1",
                "missing_field": "password1",
            },
            {
                "id": "missing-password2",
                "missing_field": "password2",
            },
        ]

        # Act
        for case in cases:
            with self.subTest(case_id=case["id"]):
                data = dict(base_data)
                data.pop(case["missing_field"])

                form = RegistrationForm(data=data)

                # Assert
                self.assertFalse(form.is_valid())
                self.assertIn(case["missing_field"], form.errors)

    # pylint: disable=invalid-name
    def test_registration_form_all_fields_present_and_types(self):
        # Arrange
        form = RegistrationForm()

        # Act
        fields = form.fields

        # Assert
        self.assertIn("company_name", fields)
        self.assertIsInstance(fields["company_name"], forms.CharField)

        self.assertIn("email", fields)
        self.assertIsInstance(fields["email"], forms.EmailField)

        # These come from UserCreationForm
        self.assertIn("password1", fields)
        self.assertIn("password2", fields)


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