defmodule Towerops.Workers.PreseemSyncWorkerTest do
  use Towerops.DataCase, async: true
  use Oban.Testing, repo: Towerops.Repo

  import Towerops.AccountsFixtures
  import Towerops.IntegrationsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Preseem.Client
  alias Towerops.Workers.PreseemSyncWorker

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)
    %{org: org}
  end

  describe "perform/1 dispatcher (cron)" do
    test "enqueues individual sync jobs for enabled integrations", %{org: org} do
      integration = integration_fixture(org.id)

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

      # Should have enqueued a job with this integration's ID
      assert [job] = all_enqueued(worker: PreseemSyncWorker)
      assert job.args == %{"integration_id" => integration.id}
      assert job.scheduled_at
    end

    test "staggers jobs across the 600-second window", %{org: org} do
      # Create a second org with its own integration
      user2 = user_fixture()
      org2 = organization_fixture(user2.id)

      _int1 = integration_fixture(org.id)
      _int2 = integration_fixture(org2.id)

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

      jobs = all_enqueued(worker: PreseemSyncWorker)
      assert length(jobs) == 2

      # Jobs should have scheduled_at times within 0-600 seconds from now
      now = DateTime.utc_now()

      for job <- jobs do
        diff = DateTime.diff(job.scheduled_at, now, :second)
        assert diff >= 0 and diff < 600, "Expected offset in [0, 600), got #{diff}"
      end
    end

    test "skips integrations synced recently", %{org: org} do
      _integration =
        integration_fixture(org.id, %{
          last_synced_at: DateTime.truncate(DateTime.utc_now(), :second),
          last_sync_status: "success"
        })

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

      # No jobs should be enqueued for recently-synced integrations
      assert [] = all_enqueued(worker: PreseemSyncWorker)
    end

    test "handles no enabled integrations" do
      assert :ok = perform_job(PreseemSyncWorker, %{})
      assert [] = all_enqueued(worker: PreseemSyncWorker)
    end

    test "respects sync_interval_minutes", %{org: org} do
      # Last synced 5 minutes ago with a 10-minute interval -> should skip
      five_minutes_ago =
        DateTime.utc_now()
        |> DateTime.add(-5, :minute)
        |> DateTime.truncate(:second)

      _integration =
        integration_fixture(org.id, %{
          sync_interval_minutes: 10,
          last_synced_at: five_minutes_ago,
          last_sync_status: "success"
        })

      assert :ok = perform_job(PreseemSyncWorker, %{})
      assert [] = all_enqueued(worker: PreseemSyncWorker)
    end

    test "enqueues job when sync interval has elapsed", %{org: org} do
      # Last synced 15 minutes ago with a 10-minute interval -> should sync
      fifteen_minutes_ago =
        DateTime.utc_now()
        |> DateTime.add(-15, :minute)
        |> DateTime.truncate(:second)

      integration =
        integration_fixture(org.id, %{
          sync_interval_minutes: 10,
          last_synced_at: fifteen_minutes_ago,
          last_sync_status: "success"
        })

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

      assert [job] = all_enqueued(worker: PreseemSyncWorker)
      assert job.args == %{"integration_id" => integration.id}
    end

    test "enqueues job for integrations that have never been synced", %{org: org} do
      integration = integration_fixture(org.id)
      assert integration.last_synced_at == nil

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

      assert [job] = all_enqueued(worker: PreseemSyncWorker)
      assert job.args == %{"integration_id" => integration.id}
    end
  end

  describe "perform/1 individual sync" do
    test "syncs the given integration", %{org: org} do
      integration = integration_fixture(org.id)

      Req.Test.stub(Client, fn conn ->
        Req.Test.json(conn, [
          %{
            "element_uuid" => "ap-1",
            "name" => "Test AP",
            "system_mac_address" => "AA:BB:CC:DD:EE:FF",
            "management_ip" => "10.0.0.1"
          }
        ])
      end)

      assert :ok = perform_job(PreseemSyncWorker, %{"integration_id" => integration.id})

      updated = Repo.reload!(integration)
      assert updated.last_synced_at
      assert updated.last_sync_status in ["success", "partial"]
    end

    test "handles API errors without crashing", %{org: org} do
      integration = integration_fixture(org.id)

      Req.Test.stub(Client, fn conn ->
        conn
        |> Plug.Conn.put_status(401)
        |> Req.Test.json(%{"error" => "unauthorized"})
      end)

      assert :ok = perform_job(PreseemSyncWorker, %{"integration_id" => integration.id})
    end

    test "returns error for nonexistent integration" do
      assert {:error, :not_found} =
               perform_job(PreseemSyncWorker, %{"integration_id" => Ecto.UUID.generate()})
    end
  end
end
