from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from ansible_base.lib.utils.apps import is_rbac_installed
from ansible_base.resource_registry.utils.resource_type_serializers import AnsibleResourceForeignKeyField, SharedResourceTypeSerializer
from ansible_base.resource_registry.utils.sso_provider import get_sso_provider_server


class UserAdditionalDataSerializer(serializers.Serializer):
    """
    Additional data serializer for UserType
    """

    social_auth = serializers.ListField()

    def to_representation(self, instance):
        social_auth = []

        if hasattr(instance, "authenticator_users"):
            for social in instance.authenticator_users.all():
                sso_server, uid = get_sso_provider_server(social.provider.slug, social.uid)
                social_auth.append(
                    {
                        "uid": uid,
                        "backend_type": social.provider.type,
                        "sso_server": sso_server,
                    }
                )
        elif hasattr(instance, "social_auth"):
            for social in instance.social_auth.all():
                sso_server, uid = get_sso_provider_server(social.provider, social.uid)
                social_auth.append(
                    {
                        "uid": uid,
                        "backend_type": social.provider,
                        "sso_server": sso_server,
                    }
                )

        return {"social_auth": social_auth}


class UserType(SharedResourceTypeSerializer):
    RESOURCE_TYPE = "user"
    ADDITIONAL_DATA_SERIALIZER = UserAdditionalDataSerializer
    UNIQUE_FIELDS = ("username",)

    username = serializers.CharField()
    email = serializers.EmailField(required=False, allow_blank=True)
    first_name = serializers.CharField(required=False, allow_blank=True)
    last_name = serializers.CharField(required=False, allow_blank=True)
    is_superuser = serializers.BooleanField(required=False, default=False)
    # Commenting this out for now because Galaxy NG doesn't have a system auditor flag
    # is_platform_auditor = serializers.BooleanField()


class OrganizationType(SharedResourceTypeSerializer):
    RESOURCE_TYPE = "organization"
    UNIQUE_FIELDS = ("name",)

    name = serializers.CharField()
    description = serializers.CharField(
        default="",
        allow_blank=True,
    )


class TeamType(SharedResourceTypeSerializer):
    RESOURCE_TYPE = "team"
    UNIQUE_FIELDS = (
        "name",
        "organization",
    )

    name = serializers.CharField()
    organization = AnsibleResourceForeignKeyField("shared.organization", required=False, allow_null=True)
    description = serializers.CharField(
        default="",
        allow_blank=True,
    )


class LenientPermissionSlugListField(serializers.ListField):
    child = serializers.CharField()

    def to_internal_value(self, data):
        from ansible_base.rbac.models import DABPermission

        data = super().to_internal_value(data)
        return list(DABPermission.objects.filter(api_slug__in=data))

    def to_representation(self, value):
        return [perm.api_slug for perm in value.all() if perm is not None]


class RoleDefinitionType(SharedResourceTypeSerializer):
    RESOURCE_TYPE = "roledefinition"
    UNIQUE_FIELDS = ("name",)

    name = serializers.CharField()
    description = serializers.CharField(default="", allow_blank=True)
    managed = serializers.BooleanField()
    permissions = LenientPermissionSlugListField()

    def __init__(self, *args, **kwargs):
        if not is_rbac_installed():
            raise RuntimeError("RoleDefinitionType requires ansible_base.rbac to be installed")

        super().__init__(*args, **kwargs)

        # Set up content_type field only when rbac is available
        from ansible_base.rbac.models import DABContentType

        self.fields['content_type'] = serializers.SlugRelatedField(
            slug_field='api_slug',
            queryset=DABContentType.objects.all(),
            allow_null=True,
            default=None,
        )

    def is_valid(self, raise_exception=False):
        try:
            return super().is_valid(raise_exception=raise_exception)
        except ValidationError as e:
            if hasattr(e, 'detail') and 'content_type' in e.detail:
                fd_detail = e.detail['content_type'][0]
                if fd_detail.code == "does_not_exist":
                    from ansible_base.resource_registry.tasks.sync import SkipResource

                    raise SkipResource(*e.args)
            raise


class FeatureFlagType(SharedResourceTypeSerializer):
    RESOURCE_TYPE = "aapflag"
    UNIQUE_FIELDS = (
        "name",
        "condition",
    )

    name = serializers.CharField()
    condition = serializers.CharField()
    value = serializers.CharField()
    required = serializers.BooleanField()
    support_level = serializers.CharField()
    visibility = serializers.CharField()
    toggle_type = serializers.CharField()
    description = serializers.CharField()
    labels = serializers.JSONField()
