import graphene
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_relay_endpoint.configurators.object_types import DjangoClientIDMutation
from typing import Type
from django.core.exceptions import ValidationError



def configure_create_mutation(
        input_object_type: Type[graphene.InputObjectType],
        abstract_mutation_type: Type[DjangoClientIDMutation], 
        conventional_name: str,
        input_field_name: str = "data",
        return_field_name: str = None,
        success_keyword: str = None,
    ) -> Type[graphene.InputObjectType]:
    """
    Configures a DjangoClientIDMutation class named <conventional_name>CreateMutation.
    The mutation extends abstract_mutation_type and implements 'mutate_and_get_payload' method, as well as Input class with input_field.

    Args:
        input_object_type (Type[graphene.InputObjectType]): 
        The InputObjectType class implementation generated by input_object_type_configurator

        abstract_mutation_type (Type[DjangoClientIDMutation]): 
        The abstract DjangoClientIDMutation class implementation generated by abstract_mutation_class_configurator

        conventional_name (str): 
        the conventional name prefixed to the final DjangoClientIDMutation class name.

        input_field_name (str, optional): 
        The input field name. Defaults to "data".

        return_field_name (str, optional): 
        The return field name. Defaults to model._meta.model_name.

    Raises:
        ValidationError: a validation error if id is provided.

    Returns:
        Type[DjangoClientIDMutation]: The actual DjangoClientIDMutation type.
    """

    @classmethod
    def mutate_and_get_payload(cls, root, info, *args, **kwargs):
        """
        The `mutate_and_get_payload` classmethod. which creates an instance or raises a validaton error, if id is provided in input.
        See <https://docs.graphene-python.org/projects/django/en/latest/mutations/#relay> for `mutate_and_get_payload`.
        """

        model = abstract_mutation_type.model
        data = kwargs.get(input_field_name or "data", None)
        client_mutation_id = kwargs.get("client_mutation_id", None)

        # as per django conventions, raise an error if user tried to provide an id. Suggest user, that instead of id, it can provide a ClientMutationId
        id = data.get("id", None)
        if id:
            raise ValidationError(_(
                "Field 'id' should not be provided when creating new objects. Instead you can provide a 'ClientMutationId' to identify the response"
                ))
        instance = cls.create_node(info)
        cls.validate(data, instance, info)
        cls.update_instance(instance, data)
        instance.save()
        mutation_kwargs = {
            return_field_name or model._meta.model_name: instance,
            success_keyword or "success": True,
            'client_mutation_id': client_mutation_id
        }
        return cls(**mutation_kwargs)
    
    Input = type("Input", (), {
        input_field_name or "data" : graphene.Field(input_object_type)
    })

    # configure the CreateMutation
    mutation = type(f'{conventional_name}CreateMutation', (abstract_mutation_type,), {
        "Input": Input,
        "mutate_and_get_payload": mutate_and_get_payload,
    })
    return mutation



