defmodule Towerops.Workers.DeviceHealthInsightWorkerTest do
  use Towerops.DataCase, async: false
  use Oban.Testing, repo: Towerops.Repo

  import Towerops.AccountsFixtures
  import Towerops.DevicesFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Devices.Device
  alias Towerops.Preseem.Insights
  alias Towerops.Workers.DeviceHealthInsightWorker

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)
    device = device_fixture(%{organization_id: org.id})

    %{org: org, device: device}
  end

  describe "perform/1" do
    test "returns :ok with no devices" do
      assert :ok = perform_job(DeviceHealthInsightWorker, %{})
    end

    test "generates device_poll_gap insight when device not polled in 24h", %{org: org, device: device} do
      stale_time = DateTime.add(DateTime.utc_now(), -25, :hour)

      Repo.update_all(
        from(d in Device, where: d.id == ^device.id),
        set: [last_snmp_poll_at: stale_time, monitoring_enabled: true]
      )

      assert :ok = perform_job(DeviceHealthInsightWorker, %{})

      insights = Insights.list_insights(org.id, type: "device_poll_gap")
      assert length(insights) == 1
      assert hd(insights).source == "snmp"
      assert hd(insights).device_id == device.id
    end

    test "does not generate poll_gap insight when device was recently polled", %{org: org, device: device} do
      recent_time = DateTime.add(DateTime.utc_now(), -1, :hour)

      Repo.update_all(
        from(d in Device, where: d.id == ^device.id),
        set: [last_snmp_poll_at: recent_time, monitoring_enabled: true]
      )

      assert :ok = perform_job(DeviceHealthInsightWorker, %{})

      insights = Insights.list_insights(org.id, type: "device_poll_gap")
      assert Enum.empty?(insights)
    end

    test "does not duplicate insights for same device", %{org: org, device: device} do
      stale_time = DateTime.add(DateTime.utc_now(), -25, :hour)

      Repo.update_all(
        from(d in Device, where: d.id == ^device.id),
        set: [last_snmp_poll_at: stale_time, monitoring_enabled: true]
      )

      assert :ok = perform_job(DeviceHealthInsightWorker, %{})
      assert :ok = perform_job(DeviceHealthInsightWorker, %{})

      insights = Insights.list_insights(org.id, type: "device_poll_gap")
      assert length(insights) == 1
    end

    test "skips devices with monitoring disabled", %{org: org, device: device} do
      stale_time = DateTime.add(DateTime.utc_now(), -25, :hour)

      Repo.update_all(
        from(d in Device, where: d.id == ^device.id),
        set: [last_snmp_poll_at: stale_time, monitoring_enabled: false]
      )

      assert :ok = perform_job(DeviceHealthInsightWorker, %{})

      insights = Insights.list_insights(org.id, type: "device_poll_gap")
      assert Enum.empty?(insights)
    end
  end
end
