defmodule Ash.Resource.Actions.Create do
  @moduledoc "Represents a create action on a resource."
  defstruct [
    accept: nil,
    manual?: false,
    manual: nil,
    touches_resources: [],
    require_attributes: [],
    delay_global_validations?: false,
    skip_global_validations?: false,
    upsert?: false,
    upsert_identity: nil,
    upsert_fields: nil,
    arguments: [],
    changes: [],
    allow_nil_input: [],
    reject: [],
    metadata: [],
    transaction?: true,
    type: :create

  @type t :: %__MODULE__{
          type: :create,
          name: atom,
          accept: list(atom),
          manual: module | nil,
          upsert?: boolean,
          delay_global_validations?: boolean,
          skip_global_validations?: boolean,
          upsert_identity: atom | nil,
          upsert_fields: nil | list(atom),
          allow_nil_input: list(atom),
          touches_resources: list(atom),
          arguments: list(Ash.Resource.Actions.Argument.t()),
          primary?: boolean,
          description: String.t() | nil

  import Ash.Resource.Actions.SharedOptions

  @global_opts shared_options()
  @create_update_opts create_update_opts()

  @opt_schema [
                allow_nil_input: [
                  type: {:list, :atom},
                  doc: """
                  A list of attributes that would normally be required, but should not be for this action. They will still be validated just before
                  the record is created.
                manual: [
                    {:spark_function_behaviour, Ash.Resource.ManualCreate,
                     {Ash.Resource.ManualCreate.Function, 2}},
                  doc: """
                  Override the creation behavior. See the manual action guides for more. Accepts a module or module and opts, or a function that takes the changeset and context.

                  See the [manual actions guide](/documentation/topics/ for more.
                upsert?: [
                  type: :boolean,
                  default: false,
                  doc: """
                  Wether or not this action is always an upsert.

                  If this is false, the action can still be used as an upsert by passing `upsert?: true` when using it.
                  This option forces all uses of this action to be treated as an upsert
                upsert_identity: [
                  type: :atom,
                  doc: """
                  The identity to use for the upsert. Cannot be overriden by the caller. Ignored  if `upsert?` is not set to `true`.
                upsert_fields: [
                  type: {:list, :atom},
                  doc: """
                  The fields to overwrite in the case of an upsert. If not provided, all fields except for fields set by defaults will be overwritten.

                  For example `uuid_primary_key :id` gets a default value, and so we would not overwrite that.
              |> Spark.OptionsHelpers.merge_schemas(
                "Action Options"
              |> Spark.OptionsHelpers.merge_schemas(
                "Create/Update Options"

  @doc false
  def opt_schema, do: @opt_schema