defmodule Towerops.Snmp.Vlan do
  @moduledoc """
  SNMP VLAN schema for tracking VLANs discovered on network devices.

  VLANs (Virtual LANs) segment network traffic and are discovered via:
  - Q-BRIDGE-MIB (IEEE 802.1Q standard)
  - Cisco VTP MIB (Cisco-specific)

  Status values:
  - active: VLAN is operational
  - suspended: VLAN is administratively suspended
  """
  use Ecto.Schema

  import Ecto.Changeset

  alias Ecto.Association.NotLoaded
  alias Towerops.Snmp.Device

  @valid_statuses ~w(active suspended)

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "snmp_vlans" do
    field :vlan_id, :integer
    field :vlan_name, :string
    field :vlan_type, :string
    field :status, :string, default: "active"
    field :last_checked_at, :utc_datetime
    field :metadata, :map, default: %{}

    belongs_to :snmp_device, Device

    timestamps(type: :utc_datetime)
  end

  @type t :: %__MODULE__{
          id: Ecto.UUID.t(),
          vlan_id: integer(),
          vlan_name: String.t() | nil,
          vlan_type: String.t() | nil,
          status: String.t(),
          last_checked_at: DateTime.t() | nil,
          metadata: map(),
          snmp_device_id: Ecto.UUID.t(),
          snmp_device: NotLoaded.t() | Device.t(),
          inserted_at: DateTime.t(),
          updated_at: DateTime.t()
        }

  @doc false
  def changeset(vlan, attrs) do
    vlan
    |> cast(attrs, [
      :snmp_device_id,
      :vlan_id,
      :vlan_name,
      :vlan_type,
      :status,
      :last_checked_at,
      :metadata
    ])
    |> validate_required([:snmp_device_id, :vlan_id])
    |> validate_inclusion(:status, @valid_statuses)
    |> validate_number(:vlan_id,
      greater_than_or_equal_to: 1,
      less_than_or_equal_to: 4094,
      message: "must be between 1 and 4094"
    )
    |> unique_constraint([:snmp_device_id, :vlan_id])
    |> foreign_key_constraint(:snmp_device_id)
  end
end
