lib/qr_nbu/validators/field_lock.ex

defmodule QRNBU.Validators.FieldLock do
  @moduledoc """
  Validator for field lock bitmap.

  Validates field lock values used to control which fields can be edited
  in the payment application. Each bit represents a field's editability.

  Accepts both integer values and `QRNBU.FieldLock` structs.
  """

  alias QRNBU.FieldLock

  @doc """
  Validates field lock value.

  ## Rules
  - Must be an integer or `QRNBU.FieldLock` struct
  - Integer must be in range 0x0000 to 0xFFFF (0 to 65535)

  ## Examples

      iex> QRNBU.Validators.FieldLock.validate(0x1234)
      {:ok, 0x1234}

      iex> QRNBU.Validators.FieldLock.validate(0)
      {:ok, 0}

      iex> QRNBU.Validators.FieldLock.validate(65535)
      {:ok, 65535}

      iex> QRNBU.Validators.FieldLock.validate(-1)
      {:error, "Field lock must be between 0 and 65535"}

      iex> QRNBU.Validators.FieldLock.validate(65536)
      {:error, "Field lock must be between 0 and 65535"}

      iex> QRNBU.Validators.FieldLock.validate("1234")
      {:error, "Field lock must be an integer or FieldLock struct"}

      iex> QRNBU.Validators.FieldLock.validate(QRNBU.FieldLock.all())
      {:ok, 65535}

      iex> QRNBU.Validators.FieldLock.validate(QRNBU.FieldLock.preset(:editable_amount))
      {:ok, 65279}
  """
  @spec validate(integer() | FieldLock.t()) :: {:ok, integer()} | {:error, String.t()}
  def validate(%FieldLock{} = field_lock) do
    {:ok, FieldLock.to_integer(field_lock)}
  end

  def validate(lock) when is_integer(lock) do
    if lock >= 0 and lock <= 0xFFFF do
      {:ok, lock}
    else
      {:error, "Field lock must be between 0 and 65535"}
    end
  end

  def validate(_), do: {:error, "Field lock must be an integer or FieldLock struct"}
end