defmodule Towerops.Workers.CloudLatencyProbeWorkerTest do
  use Towerops.DataCase

  import Towerops.AccountsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Agents
  alias Towerops.Repo
  alias Towerops.Sites
  alias Towerops.Workers.CloudLatencyProbeWorker

  describe "perform/1" do
    test "broadcasts latency probe jobs for each online cloud poller" do
      user = user_fixture()
      org = organization_fixture(user.id)
      {:ok, cloud_poller, _token} = Agents.create_cloud_poller("Cloud 1")

      cloud_poller
      |> Ecto.Changeset.change(%{last_seen_at: DateTime.truncate(DateTime.utc_now(), :second)})
      |> Repo.update!()

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

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: org.id,
          snmp_enabled: true,
          snmp_community: "public",
          snmp_version: "2c",
          monitoring_enabled: true
        })

      # Subscribe to the probe topic for this cloud poller
      Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{cloud_poller.id}:latency_probe")

      assert :ok == CloudLatencyProbeWorker.perform(%Oban.Job{})

      # Should receive probe jobs containing the device
      assert_receive {:latency_probe_jobs, devices}, 1000
      device_ids = Enum.map(devices, & &1.id)
      assert device.id in device_ids
    end

    test "does nothing when no cloud pollers are online" do
      user = user_fixture()
      org = organization_fixture(user.id)
      {:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: org.id})

      {:ok, _device} =
        Towerops.Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: org.id,
          snmp_enabled: true,
          snmp_community: "public",
          snmp_version: "2c",
          monitoring_enabled: true
        })

      assert :ok == CloudLatencyProbeWorker.perform(%Oban.Job{})
    end

    test "does nothing when no cloud-polled devices exist" do
      {:ok, cloud_poller, _token} = Agents.create_cloud_poller("Cloud 1")

      cloud_poller
      |> Ecto.Changeset.change(%{last_seen_at: DateTime.truncate(DateTime.utc_now(), :second)})
      |> Repo.update!()

      Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{cloud_poller.id}:latency_probe")

      assert :ok == CloudLatencyProbeWorker.perform(%Oban.Job{})

      # Should not receive any probe jobs
      refute_receive {:latency_probe_jobs, _}, 200
    end

    test "skips devices assigned to local agents" do
      user = user_fixture()
      org = organization_fixture(user.id)
      {:ok, cloud_poller, _token} = Agents.create_cloud_poller("Cloud 1")
      {:ok, local_agent, _token} = Agents.create_agent_token(org.id, "Local Agent")

      cloud_poller
      |> Ecto.Changeset.change(%{last_seen_at: DateTime.truncate(DateTime.utc_now(), :second)})
      |> Repo.update!()

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

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "Local Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: org.id,
          snmp_enabled: true,
          snmp_community: "public",
          snmp_version: "2c",
          monitoring_enabled: true
        })

      # Assign to local agent — should not be probed
      {:ok, _} = Agents.assign_device_to_agent(local_agent.id, device.id)

      Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{cloud_poller.id}:latency_probe")

      assert :ok == CloudLatencyProbeWorker.perform(%Oban.Job{})

      refute_receive {:latency_probe_jobs, _}, 200
    end
  end
end
