import copy

from drf_spectacular.utils import OpenApiResponse
from rest_framework import serializers


def _build_schema_field(schema, *, many=False, required=True, allow_null=False):
    if schema is None:
        return serializers.JSONField(required=required, allow_null=allow_null)

    if isinstance(schema, serializers.Field):
        field = copy.deepcopy(schema)
        field.required = required
        if hasattr(field, "allow_null"):
            field.allow_null = allow_null
        return field

    if isinstance(schema, serializers.BaseSerializer):
        serializer = copy.deepcopy(schema)
        serializer.required = required
        serializer.allow_null = allow_null
        return serializer

    if isinstance(schema, type) and issubclass(schema, serializers.BaseSerializer):
        return schema(many=many, required=required, allow_null=allow_null)

    raise TypeError(f"Unsupported schema type: {type(schema)!r}")


def build_message_response_serializer(name):
    return type(
        name,
        (serializers.Serializer,),
        {
            "__module__": __name__,
            "code": serializers.IntegerField(),
            "msg": serializers.CharField(),
        },
    )


def build_envelope_serializer(
    name,
    data_schema=None,
    *,
    many=False,
    data_required=True,
    allow_null=False,
):
    return type(
        name,
        (serializers.Serializer,),
        {
            "__module__": __name__,
            "code": serializers.IntegerField(),
            "msg": serializers.CharField(),
            "data": _build_schema_field(
                data_schema,
                many=many,
                required=data_required,
                allow_null=allow_null,
            ),
        },
    )


def build_task_queue_data_serializer(name, extra_fields=None):
    fields = {
        "__module__": __name__,
        "task_id": serializers.UUIDField(),
        "status_url": serializers.CharField(),
    }
    if extra_fields:
        fields.update(extra_fields)
    return type(name, (serializers.Serializer,), fields)


def build_task_status_data_serializer(name, result_schema=None):
    result_field = (
        _build_schema_field(result_schema, required=False, allow_null=True)
        if result_schema is not None
        else serializers.JSONField(required=False)
    )
    return type(
        name,
        (serializers.Serializer,),
        {
            "__module__": __name__,
            "task_id": serializers.UUIDField(),
            "status": serializers.CharField(),
            "message": serializers.CharField(required=False),
            "progress": serializers.DictField(
                child=serializers.JSONField(),
                required=False,
            ),
            "result": result_field,
            "error": serializers.CharField(required=False),
        },
    )


def build_response(serializer, description):
    return OpenApiResponse(response=serializer, description=description)
