defmodule Towerops.Snmp.Interface do
  @moduledoc """
  SNMP interface schema for network interfaces discovered via IF-MIB.

  Stores interface details (name, description, type, speed, MAC address)
  and has many interface statistics.
  """
  use Ecto.Schema

  import Ecto.Changeset

  alias Ecto.Association.NotLoaded
  alias Towerops.Snmp.Device
  alias Towerops.Snmp.InterfaceStat
  alias Towerops.Snmp.IpAddress
  alias Towerops.Snmp.Neighbor

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "snmp_interfaces" do
    field :if_index, :integer
    field :if_name, :string
    field :if_descr, :string
    field :if_alias, :string
    field :if_type, :integer
    field :if_speed, :integer
    field :if_phys_address, :string
    field :if_admin_status, :string
    field :if_oper_status, :string
    field :monitored, :boolean, default: true

    belongs_to :snmp_device, Device

    has_many :stats, InterfaceStat, foreign_key: :interface_id
    has_many :neighbors, Neighbor, foreign_key: :interface_id
    has_many :ip_addresses, IpAddress, foreign_key: :snmp_interface_id

    timestamps(type: :utc_datetime)
  end

  @type t :: %__MODULE__{
          id: Ecto.UUID.t(),
          if_index: integer(),
          if_name: String.t() | nil,
          if_descr: String.t() | nil,
          if_alias: String.t() | nil,
          if_type: integer() | nil,
          if_speed: integer() | nil,
          if_phys_address: String.t() | nil,
          if_admin_status: String.t() | nil,
          if_oper_status: String.t() | nil,
          monitored: boolean(),
          snmp_device_id: Ecto.UUID.t(),
          snmp_device: NotLoaded.t() | Device.t(),
          stats: NotLoaded.t() | [InterfaceStat.t()],
          inserted_at: DateTime.t(),
          updated_at: DateTime.t()
        }

  @doc false
  def changeset(interface, attrs) do
    interface
    |> cast(attrs, [
      :snmp_device_id,
      :if_index,
      :if_name,
      :if_descr,
      :if_alias,
      :if_type,
      :if_speed,
      :if_phys_address,
      :if_admin_status,
      :if_oper_status,
      :monitored
    ])
    |> validate_required([:snmp_device_id, :if_index])
    |> unique_constraint([:snmp_device_id, :if_index])
    |> foreign_key_constraint(:snmp_device_id)
  end
end
