defmodule Towerops.Agents.AgentAssignment do
  @moduledoc """
  Schema for assigning devices to remote agents.

  Each device can only be assigned to one agent at a time (unique constraint on device_id).
  This ensures that polling is not duplicated across multiple agents.
  """
  use Ecto.Schema

  import Ecto.Changeset

  alias Ecto.Association.NotLoaded
  alias Towerops.Agents.AgentToken
  alias Towerops.Devices.Device

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "agent_assignments" do
    field :enabled, :boolean, default: true

    belongs_to :agent_token, AgentToken
    belongs_to :device, Device

    timestamps(type: :utc_datetime)
  end

  @type t :: %__MODULE__{
          id: Ecto.UUID.t(),
          enabled: boolean(),
          agent_token_id: Ecto.UUID.t(),
          agent_token: NotLoaded.t() | AgentToken.t(),
          device_id: Ecto.UUID.t(),
          device: NotLoaded.t() | Device.t(),
          inserted_at: DateTime.t(),
          updated_at: DateTime.t()
        }

  @doc """
  Changeset for creating and updating agent assignments.

  ## Examples

      iex> changeset(%AgentAssignment{}, %{agent_token_id: token_id, device_id: equip_id})
      %Ecto.Changeset{valid?: true}

  """
  def changeset(assignment, attrs) do
    assignment
    |> cast(attrs, [:agent_token_id, :device_id, :enabled])
    |> validate_required([:agent_token_id, :device_id])
    |> unique_constraint([:device_id])
    |> foreign_key_constraint(:agent_token_id)
    |> foreign_key_constraint(:device_id)
  end
end
