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

  import Ecto.Query
  import Towerops.AccountsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Agents
  alias Towerops.Agents.AgentToken
  alias Towerops.Preseem.Insights
  alias Towerops.Workers.SystemInsightWorker

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)

    %{org: org}
  end

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

    test "generates agent_offline insight for stale agent", %{org: org} do
      {:ok, agent, _token} = Agents.create_agent_token(org.id, "Offline Agent")

      stale_time = DateTime.add(DateTime.utc_now(), -15, :minute)

      Repo.update_all(
        from(a in AgentToken, where: a.id == ^agent.id),
        set: [last_seen_at: stale_time]
      )

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

      insights = Insights.list_insights(org.id, type: "agent_offline")
      assert length(insights) == 1
      assert hd(insights).source == "system"
      assert hd(insights).agent_token_id == agent.id
    end

    test "does not generate insight for fresh agent", %{org: org} do
      {:ok, agent, _token} = Agents.create_agent_token(org.id, "Fresh Agent")
      Agents.update_agent_token_heartbeat(agent.id, "192.168.1.1", %{})

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

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

    test "auto-resolves insight when agent comes back online", %{org: org} do
      {:ok, agent, _token} = Agents.create_agent_token(org.id, "Recovering Agent")

      # First: agent goes offline
      stale_time = DateTime.add(DateTime.utc_now(), -15, :minute)

      Repo.update_all(
        from(a in AgentToken, where: a.id == ^agent.id),
        set: [last_seen_at: stale_time]
      )

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

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

      # Then: agent comes back online
      Agents.update_agent_token_heartbeat(agent.id, "192.168.1.1", %{})

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

      # Should be resolved now
      active_insights = Insights.list_insights(org.id, type: "agent_offline")
      assert Enum.empty?(active_insights)

      resolved_insights = Insights.list_insights(org.id, type: "agent_offline", status: "resolved")
      assert length(resolved_insights) == 1
    end

    test "does not duplicate insights for same agent", %{org: org} do
      {:ok, agent, _token} = Agents.create_agent_token(org.id, "Still Offline")

      stale_time = DateTime.add(DateTime.utc_now(), -15, :minute)

      Repo.update_all(
        from(a in AgentToken, where: a.id == ^agent.id),
        set: [last_seen_at: stale_time]
      )

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

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