defmodule Towerops.Alerts.AlertTest do
  use Towerops.DataCase, async: true

  alias Towerops.Alerts.Alert

  describe "changeset/2" do
    test "valid changeset with required fields" do
      attrs = %{
        device_id: Ecto.UUID.generate(),
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z]
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      assert changeset.valid?
      assert changeset.changes.device_id == attrs.device_id
      assert changeset.changes.alert_type == :device_down
      assert changeset.changes.triggered_at == attrs.triggered_at
    end

    test "valid changeset with all fields" do
      device_id = Ecto.UUID.generate()
      user_id = Ecto.UUID.generate()
      triggered_at = ~U[2026-01-15 10:00:00Z]
      acknowledged_at = ~U[2026-01-15 10:05:00Z]
      resolved_at = ~U[2026-01-15 10:10:00Z]
      email_sent_at = ~U[2026-01-15 10:01:00Z]

      attrs = %{
        device_id: device_id,
        alert_type: :device_up,
        triggered_at: triggered_at,
        acknowledged_at: acknowledged_at,
        acknowledged_by_id: user_id,
        resolved_at: resolved_at,
        email_sent_at: email_sent_at,
        message: "Device came back online"
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      assert changeset.valid?
      assert changeset.changes.device_id == device_id
      assert changeset.changes.alert_type == :device_up
      assert changeset.changes.triggered_at == triggered_at
      assert changeset.changes.acknowledged_at == acknowledged_at
      assert changeset.changes.acknowledged_by_id == user_id
      assert changeset.changes.resolved_at == resolved_at
      assert changeset.changes.email_sent_at == email_sent_at
      assert changeset.changes.message == "Device came back online"
    end

    test "requires device_id" do
      attrs = %{
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z]
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      refute changeset.valid?
      assert %{device_id: ["can't be blank"]} = errors_on(changeset)
    end

    test "requires alert_type" do
      attrs = %{
        device_id: Ecto.UUID.generate(),
        triggered_at: ~U[2026-01-15 10:00:00Z]
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      refute changeset.valid?
      assert %{alert_type: ["can't be blank"]} = errors_on(changeset)
    end

    test "requires triggered_at" do
      attrs = %{
        device_id: Ecto.UUID.generate(),
        alert_type: :device_down
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      refute changeset.valid?
      assert %{triggered_at: ["can't be blank"]} = errors_on(changeset)
    end

    test "validates alert_type is one of valid enum values" do
      attrs = %{
        device_id: Ecto.UUID.generate(),
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z]
      }

      changeset = Alert.changeset(%Alert{}, attrs)
      assert changeset.valid?

      attrs2 = %{attrs | alert_type: :device_up}
      changeset2 = Alert.changeset(%Alert{}, attrs2)
      assert changeset2.valid?
    end

    test "accepts nil for optional fields" do
      attrs = %{
        device_id: Ecto.UUID.generate(),
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z],
        acknowledged_at: nil,
        acknowledged_by_id: nil,
        resolved_at: nil,
        email_sent_at: nil,
        message: nil
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      assert changeset.valid?
    end

    test "allows updating an existing alert" do
      device_id = Ecto.UUID.generate()

      existing_alert = %Alert{
        id: Ecto.UUID.generate(),
        device_id: device_id,
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z]
      }

      user_id = Ecto.UUID.generate()

      attrs = %{
        acknowledged_at: ~U[2026-01-15 10:05:00Z],
        acknowledged_by_id: user_id,
        message: "Acknowledged by admin"
      }

      changeset = Alert.changeset(existing_alert, attrs)

      assert changeset.valid?
      assert changeset.changes.acknowledged_at == attrs.acknowledged_at
      assert changeset.changes.acknowledged_by_id == user_id
      assert changeset.changes.message == "Acknowledged by admin"
    end

    test "casts all supported fields" do
      device_id = Ecto.UUID.generate()
      user_id = Ecto.UUID.generate()

      attrs = %{
        device_id: device_id,
        alert_type: :device_down,
        triggered_at: ~U[2026-01-15 10:00:00Z],
        acknowledged_at: ~U[2026-01-15 10:05:00Z],
        acknowledged_by_id: user_id,
        resolved_at: ~U[2026-01-15 10:10:00Z],
        email_sent_at: ~U[2026-01-15 10:01:00Z],
        message: "Test message"
      }

      changeset = Alert.changeset(%Alert{}, attrs)

      assert changeset.valid?

      # All fields should be in changes
      assert Map.has_key?(changeset.changes, :device_id)
      assert Map.has_key?(changeset.changes, :alert_type)
      assert Map.has_key?(changeset.changes, :triggered_at)
      assert Map.has_key?(changeset.changes, :acknowledged_at)
      assert Map.has_key?(changeset.changes, :acknowledged_by_id)
      assert Map.has_key?(changeset.changes, :resolved_at)
      assert Map.has_key?(changeset.changes, :email_sent_at)
      assert Map.has_key?(changeset.changes, :message)
    end
  end
end
