from unittest.mock import Mock

import jsonschema
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models

from servala.core.crd import generate_custom_form_class
from servala.core.crd.forms import DEFAULT_FIELD_CONFIGS
from servala.core.forms import ServiceDefinitionAdminForm
from servala.core.models import ControlPlaneCRD


def test_custom_model_form_class_returns_class_when_form_config_exists():

    crd = Mock(spec=ControlPlaneCRD)
    service_def = Mock()
    service_def.form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    }
                ],
            }
        ]
    }
    crd.service_definition = service_def

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)

        class Meta:
            app_label = "test"

    crd.django_model = TestModel
    result = generate_custom_form_class(
        crd.service_definition.form_config, crd.django_model
    )

    assert result is not None
    assert hasattr(result, "form_config")


def test_form_config_schema_validates_minimal_config():
    form = ServiceDefinitionAdminForm()
    schema = form.form_config_schema

    minimal_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Service Name",
                        "controlplane_field_mapping": "spec.serviceName",
                    }
                ]
            }
        ]
    }

    jsonschema.validate(instance=minimal_config, schema=schema)


def test_form_config_schema_validates_config_with_null_integers():
    form = ServiceDefinitionAdminForm()
    schema = form.form_config_schema

    config_with_nulls = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Service Name",
                        "controlplane_field_mapping": "spec.serviceName",
                        "max_length": None,
                        "required": False,
                    },
                    {
                        "type": "textarea",
                        "label": "Description",
                        "controlplane_field_mapping": "spec.description",
                        "rows": None,
                        "max_length": None,
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "spec.port",
                        "min_value": None,
                        "max_value": None,
                    },
                    {
                        "type": "array",
                        "label": "Tags",
                        "controlplane_field_mapping": "spec.tags",
                        "min_values": None,
                        "max_values": None,
                    },
                ]
            }
        ]
    }

    jsonschema.validate(instance=config_with_nulls, schema=schema)


def test_form_config_schema_validates_full_config():
    form = ServiceDefinitionAdminForm()
    schema = form.form_config_schema

    full_config = {
        "fieldsets": [
            {
                "title": "Service Configuration",
                "fields": [
                    {
                        "type": "text",
                        "label": "Service Name",
                        "controlplane_field_mapping": "spec.serviceName",
                        "help_text": "Enter a unique service name",
                        "required": True,
                        "max_length": 100,
                    },
                    {
                        "type": "email",
                        "label": "Admin Email",
                        "controlplane_field_mapping": "spec.adminEmail",
                        "help_text": "Contact email for service administrator",
                        "required": True,
                        "max_length": 255,
                    },
                    {
                        "type": "textarea",
                        "label": "Description",
                        "controlplane_field_mapping": "spec.description",
                        "help_text": "Describe the service purpose",
                        "required": False,
                        "rows": 5,
                        "max_length": 500,
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "spec.port",
                        "help_text": "Service port number",
                        "required": True,
                        "min_value": 1,
                        "max_value": 65535,
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "spec.environment",
                        "help_text": "Deployment environment",
                        "required": True,
                        "choices": [
                            ["dev", "Development"],
                            ["staging", "Staging"],
                            ["prod", "Production"],
                        ],
                    },
                    {
                        "type": "checkbox",
                        "label": "Enable Monitoring",
                        "controlplane_field_mapping": "spec.monitoring.enabled",
                        "help_text": "Enable service monitoring",
                        "required": False,
                    },
                    {
                        "type": "array",
                        "label": "Tags",
                        "controlplane_field_mapping": "spec.tags",
                        "help_text": "Service tags for organization",
                        "required": False,
                        "min_values": 0,
                        "max_values": 10,
                    },
                ],
            }
        ]
    }
    jsonschema.validate(instance=full_config, schema=schema)


def test_choice_field_uses_custom_choices_from_form_config():
    """Test that choice fields use custom choices when provided in form_config"""

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        environment = models.CharField(
            max_length=20,
            choices=[
                ("dev", "Development"),
                ("staging", "Staging"),
                ("prod", "Production"),
                ("test", "Testing"),
            ],
        )

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "environment",
                        "required": True,
                        "choices": [["dev", "Development"], ["prod", "Production"]],
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class()

    environment_field = form.fields["environment"]
    assert list(environment_field.choices) == [
        ("dev", "Development"),
        ("prod", "Production"),
    ]

    assert hasattr(environment_field, "_controlplane_choices")
    assert len(environment_field._controlplane_choices) == 5  # 4 choices + empty choice


def test_choice_field_uses_control_plane_choices_when_no_custom_choices():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        environment = models.CharField(
            max_length=20,
            choices=[
                ("dev", "Development"),
                ("staging", "Staging"),
                ("prod", "Production"),
            ],
        )

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "environment",
                        "required": True,
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class()

    environment_field = form.fields["environment"]
    choices_list = list(environment_field.choices)
    assert len(choices_list) == 4  # 3 choices + empty choice
    assert ("dev", "Development") in choices_list


def test_choice_field_validates_against_control_plane_choices():
    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        environment = models.CharField(
            max_length=20,
            choices=[
                ("dev", "Development"),
                ("staging", "Staging"),
                ("prod", "Production"),
            ],
        )

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "environment",
                        "required": True,
                        "choices": [["dev", "Development"], ["prod", "Production"]],
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)

    form = form_class(data={"display_name": "test-service", "environment": "dev"})
    form.fields["context"].required = False  # Skip context validation
    assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"

    form = form_class(data={"display_name": "test-service", "environment": "prod"})
    form.fields["context"].required = False  # Skip context validation
    assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"

    form = form_class(data={"display_name": "test-service", "environment": "invalid"})
    form.fields["context"].required = False  # Skip context validation
    assert not form.is_valid()
    assert "environment" in form.errors


def test_admin_form_validates_choice_values_against_schema():

    form = ServiceDefinitionAdminForm()
    mock_crd = Mock()
    mock_crd.resource_schema = {
        "properties": {
            "spec": {
                "properties": {
                    "environment": {
                        "type": "string",
                        "enum": ["dev", "staging", "prod"],
                    }
                }
            }
        }
    }

    valid_form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "spec.environment",
                        "choices": [["dev", "Development"], ["prod", "Production"]],
                    },
                ]
            }
        ]
    }

    spec_schema = mock_crd.resource_schema["properties"]["spec"]
    errors = []

    for field in valid_form_config["fieldsets"][0]["fields"]:
        if field.get("type") == "choice":
            form._validate_choice_field(
                field, field["controlplane_field_mapping"], spec_schema, "spec", errors
            )

    assert len(errors) == 0, f"Expected no errors but got: {errors}"

    invalid_form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "spec.environment",
                        "choices": [
                            ["dev", "Development"],
                            ["invalid", "Invalid Environment"],
                        ],
                    },
                ]
            }
        ]
    }

    errors = []

    for field in invalid_form_config["fieldsets"][0]["fields"]:
        if field.get("type") == "choice":
            form._validate_choice_field(
                field, field["controlplane_field_mapping"], spec_schema, "spec", errors
            )

    assert len(errors) > 0, "Expected validation errors but got none"
    error_message = str(errors[0])
    assert "invalid" in error_message.lower()
    assert "Environment" in error_message


def test_number_field_min_max_sets_widget_attributes():
    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        port = models.IntegerField()
        replica_count = models.IntegerField()

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "port",
                        "required": True,
                        "min_value": 1,
                        "max_value": 65535,
                    },
                    {
                        "type": "number",
                        "label": "Replicas",
                        "controlplane_field_mapping": "replica_count",
                        "required": True,
                        "min_value": 1,
                        "max_value": 10,
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class()

    port_field = form.fields["port"]
    assert port_field.widget.attrs.get("min") == 1
    assert port_field.widget.attrs.get("max") == 65535

    replica_field = form.fields["replica_count"]
    assert replica_field.widget.attrs.get("min") == 1
    assert replica_field.widget.attrs.get("max") == 10

    port_validators = port_field.validators
    assert any(
        isinstance(v, MinValueValidator) and v.limit_value == 1 for v in port_validators
    )
    assert any(
        isinstance(v, MaxValueValidator) and v.limit_value == 65535
        for v in port_validators
    )


def test_default_value_for_all_field_types():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        description = models.TextField()
        port = models.IntegerField()
        environment = models.CharField(
            max_length=20,
            choices=[
                ("dev", "Development"),
                ("staging", "Staging"),
                ("prod", "Production"),
            ],
        )
        monitoring_enabled = models.BooleanField()
        tags = models.JSONField()

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "default_value": "default-name",
                    },
                    {
                        "type": "textarea",
                        "label": "Description",
                        "controlplane_field_mapping": "description",
                        "default_value": "Default description text",
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "port",
                        "default_value": "8080",
                    },
                    {
                        "type": "choice",
                        "label": "Environment",
                        "controlplane_field_mapping": "environment",
                        "default_value": "dev",
                    },
                    {
                        "type": "checkbox",
                        "label": "Enable Monitoring",
                        "controlplane_field_mapping": "monitoring_enabled",
                        "default_value": "true",
                    },
                    {
                        "type": "array",
                        "label": "Tags",
                        "controlplane_field_mapping": "tags",
                        "default_value": "tag1,tag2,tag3",
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class()

    assert form.fields["display_name"].initial == "default-name"
    assert form.fields["description"].initial == "Default description text"
    assert form.fields["port"].initial == "8080"
    assert form.fields["environment"].initial == "dev"
    assert form.fields["monitoring_enabled"].initial == "true"
    assert form.fields["tags"].initial == "tag1,tag2,tag3"


def test_default_value_not_override_existing_instance():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        port = models.IntegerField()

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "default_value": "default-name",
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "port",
                        "default_value": "8080",
                    },
                ],
            }
        ]
    }

    instance = TestModel(display_name="existing-name", port=3000)
    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class(instance=instance)

    assert form.initial["display_name"] == "existing-name"
    assert form.initial["port"] == 3000


def test_form_config_coerces_string_numbers_to_integers():
    form = ServiceDefinitionAdminForm()
    schema = form.form_config_schema

    config_with_string_numbers = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Service Name",
                        "controlplane_field_mapping": "spec.serviceName",
                        "max_length": "64",  # String instead of integer
                        "required": True,
                    },
                    {
                        "type": "textarea",
                        "label": "Description",
                        "controlplane_field_mapping": "spec.description",
                        "rows": "5",  # String instead of integer
                        "max_length": "500",  # String instead of integer
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "spec.port",
                        "min_value": "1",  # String instead of integer
                        "max_value": "65535",  # String instead of integer
                    },
                    {
                        "type": "array",
                        "label": "Tags",
                        "controlplane_field_mapping": "spec.tags",
                        "min_values": "0",  # String instead of integer
                        "max_values": "10",  # String instead of integer
                    },
                ]
            }
        ]
    }

    normalized_config = form._normalize_form_config_types(config_with_string_numbers)
    fields = normalized_config["fieldsets"][0]["fields"]

    assert fields[0]["max_length"] == 64
    assert isinstance(fields[0]["max_length"], int)

    assert fields[1]["rows"] == 5
    assert isinstance(fields[1]["rows"], int)
    assert fields[1]["max_length"] == 500
    assert isinstance(fields[1]["max_length"], int)

    assert fields[2]["min_value"] == 1
    assert isinstance(fields[2]["min_value"], int)
    assert fields[2]["max_value"] == 65535
    assert isinstance(fields[2]["max_value"], int)

    assert fields[3]["min_values"] == 0
    assert isinstance(fields[3]["min_values"], int)
    assert fields[3]["max_values"] == 10
    assert isinstance(fields[3]["max_values"], int)

    jsonschema.validate(instance=normalized_config, schema=schema)


def test_form_config_handles_float_numbers():
    form = ServiceDefinitionAdminForm()

    config_with_floats = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "number",
                        "label": "Price",
                        "controlplane_field_mapping": "spec.price",
                        "min_value": "0.01",  # String float
                        "max_value": "999.99",  # String float
                    },
                ]
            }
        ]
    }

    normalized_config = form._normalize_form_config_types(config_with_floats)
    field = normalized_config["fieldsets"][0]["fields"][0]

    assert field["min_value"] == 0.01
    assert isinstance(field["min_value"], float)
    assert field["max_value"] == 999.99
    assert isinstance(field["max_value"], float)


def test_form_config_handles_empty_string_as_none():
    form = ServiceDefinitionAdminForm()

    config_with_empty_strings = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "max_length": "",  # Empty string
                    },
                ]
            }
        ]
    }

    normalized_config = form._normalize_form_config_types(config_with_empty_strings)
    field = normalized_config["fieldsets"][0]["fields"][0]
    assert field["max_length"] is None


def test_single_element_choices_are_normalized():
    form = ServiceDefinitionAdminForm()
    mock_crd = Mock()
    mock_crd.resource_schema = {
        "properties": {
            "spec": {
                "properties": {
                    "version": {
                        "type": "string",
                        "enum": ["6.2", "7.0", "7.2"],
                    }
                }
            }
        }
    }

    config_with_single_choices = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                    },
                    {
                        "type": "choice",
                        "label": "Version",
                        "controlplane_field_mapping": "spec.version",
                        "choices": [["6.2"]],  # Single element - should be transformed
                    },
                ]
            }
        ]
    }

    spec_schema = mock_crd.resource_schema["properties"]["spec"]
    errors = []

    for field in config_with_single_choices["fieldsets"][0]["fields"]:
        if field.get("type") == "choice":
            form._validate_choice_field(
                field, field["controlplane_field_mapping"], spec_schema, "spec", errors
            )

    assert len(errors) == 0, f"Expected no errors but got: {errors}"
    version_field = config_with_single_choices["fieldsets"][0]["fields"][1]
    assert version_field["choices"] == [["6.2", "6.2"]]


def test_two_element_choices_work_correctly():
    form = ServiceDefinitionAdminForm()
    mock_crd = Mock()
    mock_crd.resource_schema = {
        "properties": {
            "spec": {
                "properties": {
                    "version": {
                        "type": "string",
                        "enum": ["6.2", "7.0"],
                    }
                }
            }
        }
    }

    config_with_proper_choices = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "choice",
                        "label": "Version",
                        "controlplane_field_mapping": "spec.version",
                        "choices": [["6.2", "Version 6.2"], ["7.0", "Version 7.0"]],
                    },
                ]
            }
        ]
    }

    spec_schema = mock_crd.resource_schema["properties"]["spec"]
    errors = []

    for field in config_with_proper_choices["fieldsets"][0]["fields"]:
        assert field["type"] == "choice"
        form._validate_choice_field(
            field, field["controlplane_field_mapping"], spec_schema, "spec", errors
        )

    assert len(errors) == 0, f"Expected no errors but got: {errors}"
    version_field = config_with_proper_choices["fieldsets"][0]["fields"][0]
    assert version_field["choices"] == [["6.2", "Version 6.2"], ["7.0", "Version 7.0"]]


def test_empty_choices_fail_validation():
    form = ServiceDefinitionAdminForm()
    config_with_empty_choice = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "choice",
                        "label": "Version",
                        "controlplane_field_mapping": "spec.version",
                        "choices": [[]],  # Empty choice - invalid
                    },
                ]
            }
        ]
    }

    errors = []

    for field in config_with_empty_choice["fieldsets"][0]["fields"]:
        assert field["type"] == "choice"
        form._validate_choice_field(
            field, field["controlplane_field_mapping"], {}, "spec", errors
        )

    assert len(errors) > 0
    assert "must have 1 or 2 elements" in str(errors[0])


def test_three_plus_element_choices_fail_validation():
    form = ServiceDefinitionAdminForm()
    config_with_long_choice = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "choice",
                        "label": "Version",
                        "controlplane_field_mapping": "spec.version",
                        "choices": [
                            ["6.2", "Version 6.2", "Extra"]
                        ],  # 3 elements - invalid
                    },
                ]
            }
        ]
    }

    errors = []

    for field in config_with_long_choice["fieldsets"][0]["fields"]:
        assert field["type"] == "choice"
        form._validate_choice_field(
            field, field["controlplane_field_mapping"], {}, "spec", errors
        )

    assert len(errors) > 0
    assert "must have 1 or 2 elements" in str(errors[0])


def test_field_with_default_config_only_needs_mapping():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)

        class Meta:
            app_label = "test"

    minimal_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "controlplane_field_mapping": "display_name",
                    },
                ]
            }
        ]
    }

    form_class = generate_custom_form_class(minimal_config, TestModel)
    form = form_class()

    name_field = form.fields["display_name"]
    assert name_field.label == DEFAULT_FIELD_CONFIGS["display_name"]["label"]
    assert name_field.help_text == DEFAULT_FIELD_CONFIGS["display_name"]["help_text"]
    assert name_field.required == DEFAULT_FIELD_CONFIGS["display_name"]["required"]


def test_field_with_default_config_can_override_defaults():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)

        class Meta:
            app_label = "test"

    override_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "controlplane_field_mapping": "display_name",
                        "label": "Custom Name Label",
                        "required": False,
                    },
                ]
            }
        ]
    }

    form_class = generate_custom_form_class(override_config, TestModel)
    form = form_class()

    name_field = form.fields["display_name"]
    assert name_field.label == "Custom Name Label"
    assert name_field.required is False
    assert name_field.help_text == DEFAULT_FIELD_CONFIGS["display_name"]["help_text"]


def test_empty_values_dont_override_default_configs():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)

        class Meta:
            app_label = "test"

    admin_form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "controlplane_field_mapping": "display_name",
                        "type": "",
                        "label": "",
                        "help_text": None,
                        "max_length": None,
                        "required": False,
                    },
                ]
            }
        ]
    }

    form_class = generate_custom_form_class(admin_form_config, TestModel)
    form = form_class()

    name_field = form.fields["display_name"]

    assert name_field.label == DEFAULT_FIELD_CONFIGS["display_name"]["label"]
    assert name_field.help_text == DEFAULT_FIELD_CONFIGS["display_name"]["help_text"]
    assert name_field.max_length == DEFAULT_FIELD_CONFIGS["display_name"]["max_length"]

    assert name_field.required is False  # Was overridden by explicit False


def test_number_field_validates_min_max_values():

    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        port = models.IntegerField()

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "title": "General",
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "number",
                        "label": "Port",
                        "controlplane_field_mapping": "port",
                        "required": True,
                        "min_value": "1",
                        "max_value": "65535",
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)

    # Test value below minimum fails validation
    form = form_class(data={"display_name": "test-service", "port": 0})
    form.fields["context"].required = False
    assert not form.is_valid()
    assert "port" in form.errors

    # Test value above maximum fails validation
    form = form_class(data={"display_name": "test-service", "port": 65536})
    form.fields["context"].required = False
    assert not form.is_valid()
    assert "port" in form.errors

    # Test valid value passes validation
    form = form_class(data={"display_name": "test-service", "port": 8080})
    form.fields["context"].required = False
    assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"


def test_number_field_with_addon_text_roundtrip():
    class TestModel(models.Model):
        display_name = models.CharField(max_length=100)
        disk_size = models.IntegerField()

        class Meta:
            app_label = "test"

    form_config = {
        "fieldsets": [
            {
                "fields": [
                    {
                        "type": "text",
                        "label": "Name",
                        "controlplane_field_mapping": "display_name",
                        "required": True,
                    },
                    {
                        "type": "number",
                        "label": "Disk Size",
                        "controlplane_field_mapping": "disk_size",
                        "addon_text": "Gi",
                    },
                ],
            }
        ]
    }

    form_class = generate_custom_form_class(form_config, TestModel)
    form = form_class(initial={"name": "test-instance", "disk_size": "25Gi"})

    assert form.initial["disk_size"] == 25
    form = form_class(data={"display_name": "test-instance", "disk_size": "25"})
    form.fields["context"].required = False
    assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"
    nested_data = form.get_nested_data()
    assert nested_data["disk_size"] == "25Gi"
