defmodule Towerops.AlertsTest do
  use Towerops.DataCase

  alias Towerops.Alerts

  describe "alerts" do
    import Towerops.AccountsFixtures

    alias Towerops.Alerts.Alert

    setup do
      user = user_fixture()
      {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "Router 1",
          ip_address: "192.168.1.1",
          site_id: site.id
        })

      %{device: device, organization: organization, user: user}
    end

    @valid_attrs %{
      alert_type: :device_down,
      triggered_at: ~U[2025-12-21 12:00:00Z],
      message: "Equipment is not responding"
    }

    test "create_alert/1 with valid data creates an alert", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      assert {:ok, %Alert{} = alert} = Alerts.create_alert(attrs)
      assert alert.alert_type == :device_down
      assert alert.message == "Equipment is not responding"
    end

    test "create_alert/1 with invalid data returns error changeset" do
      assert {:error, %Ecto.Changeset{}} = Alerts.create_alert(%{})
    end

    test "list_devices_alerts/2 returns alerts for device", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)
      [result] = Alerts.list_devices_alerts(device.id)
      assert result.id == alert.id
    end

    test "list_organization_active_alerts/1 returns unresolved alerts", %{
      device: device,
      organization: organization
    } do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)

      # Create resolved alert
      {:ok, resolved_alert} =
        Alerts.create_alert(Map.put(attrs, :resolved_at, ~U[2025-12-21 13:00:00Z]))

      active = Alerts.list_organization_active_alerts(organization.id)
      assert length(active) == 1
      assert hd(active).id == alert.id
      refute Enum.any?(active, fn a -> a.id == resolved_alert.id end)
    end

    test "list_organization_alerts/2 returns all alerts", %{
      device: device,
      organization: organization
    } do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, _alert1} = Alerts.create_alert(attrs)
      {:ok, _alert2} = Alerts.create_alert(Map.put(attrs, :alert_type, :device_up))

      alerts = Alerts.list_organization_alerts(organization.id, 100)
      assert length(alerts) == 2
    end

    test "get_alert!/1 returns the alert with given id", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)
      assert Alerts.get_alert!(alert.id).id == alert.id
    end

    test "acknowledge_alert/2 marks alert as acknowledged", %{device: device, user: user} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)

      assert {:ok, acknowledged} = Alerts.acknowledge_alert(alert, user.id)
      assert acknowledged.acknowledged_at
      assert acknowledged.acknowledged_by_id == user.id
    end

    test "resolve_alert/1 marks alert as resolved", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)

      assert {:ok, resolved} = Alerts.resolve_alert(alert)
      assert resolved.resolved_at
    end

    test "has_active_alert?/2 returns true when active alert exists", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, _alert} = Alerts.create_alert(attrs)

      assert Alerts.has_active_alert?(device.id, :device_down) == true
      assert Alerts.has_active_alert?(device.id, :device_up) == false
    end

    test "has_active_alert?/2 returns false for resolved alerts", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)
      {:ok, _resolved} = Alerts.resolve_alert(alert)

      assert Alerts.has_active_alert?(device.id, :device_down) == false
    end

    test "get_active_alert/2 returns active alert of specific type", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)

      found = Alerts.get_active_alert(device.id, :device_down)
      assert found.id == alert.id
    end

    test "get_active_alert/2 returns nil when no active alert exists", %{device: device} do
      assert Alerts.get_active_alert(device.id, :device_down) == nil
    end

    test "get_active_alert/2 returns nil for resolved alerts", %{device: device} do
      attrs = Map.put(@valid_attrs, :device_id, device.id)
      {:ok, alert} = Alerts.create_alert(attrs)
      {:ok, _resolved} = Alerts.resolve_alert(alert)

      assert Alerts.get_active_alert(device.id, :device_down) == nil
    end
  end
end
