defmodule Towerops.Snmp.Storage do
  @moduledoc """
  SNMP storage schema for tracking disk and filesystem usage.

  Storage is discovered via HOST-RESOURCES-MIB hrStorageTable and includes:
  - Fixed disks (HDD, SSD)
  - Removable disks (USB, external)
  - Network storage (NFS, iSCSI)
  - RAM disks and virtual memory

  Tracks total and used space for capacity monitoring.
  """
  use Ecto.Schema

  import Ecto.Changeset

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

  @valid_storage_types ~w(other ram virtual_memory fixed_disk removable_disk floppy_disk compact_disc ram_disk flash_memory network_disk)

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "snmp_storage" do
    field :storage_index, :integer
    field :storage_type, :string
    field :description, :string
    field :device_name, :string
    field :total_bytes, :integer
    field :used_bytes, :integer
    field :allocation_units, :integer
    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(),
          storage_index: integer(),
          storage_type: String.t(),
          description: String.t() | nil,
          device_name: String.t() | nil,
          total_bytes: integer() | nil,
          used_bytes: integer() | nil,
          allocation_units: integer() | nil,
          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(storage, attrs) do
    storage
    |> cast(attrs, [
      :snmp_device_id,
      :storage_index,
      :storage_type,
      :description,
      :device_name,
      :total_bytes,
      :used_bytes,
      :allocation_units,
      :last_checked_at,
      :metadata
    ])
    |> validate_required([:snmp_device_id, :storage_index, :storage_type])
    |> validate_inclusion(:storage_type, @valid_storage_types)
    |> unique_constraint([:snmp_device_id, :storage_index])
    |> foreign_key_constraint(:snmp_device_id)
  end
end
