defmodule Towerops.Snmp.StateSensor do
  @moduledoc """
  SNMP state sensor schema for monitoring device health status.

  Unlike numeric sensors that track values like temperature or voltage,
  state sensors track discrete states like power supply status, fan status,
  and module operational status.

  State values are mapped to generic status categories:
  - ok: Normal operation
  - warning: Degraded but functional
  - critical: Failed or about to fail
  - unknown: State not determined
  """
  use Ecto.Schema

  import Ecto.Changeset

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

  @valid_statuses ~w(ok warning critical unknown)

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "snmp_state_sensors" do
    field :sensor_index, :string
    field :sensor_oid, :string
    field :sensor_descr, :string
    field :entity_type, :string
    field :state_value, :integer
    field :state_descr, :string
    field :status, :string, default: "unknown"
    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(),
          sensor_index: String.t(),
          sensor_oid: String.t(),
          sensor_descr: String.t() | nil,
          entity_type: String.t() | nil,
          state_value: integer() | nil,
          state_descr: 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(state_sensor, attrs) do
    state_sensor
    |> cast(attrs, [
      :snmp_device_id,
      :sensor_index,
      :sensor_oid,
      :sensor_descr,
      :entity_type,
      :state_value,
      :state_descr,
      :status,
      :last_checked_at,
      :metadata
    ])
    |> validate_required([:snmp_device_id, :sensor_index, :sensor_oid])
    |> validate_inclusion(:status, @valid_statuses)
    |> unique_constraint([:snmp_device_id, :sensor_index])
    |> foreign_key_constraint(:snmp_device_id)
  end
end
