defmodule Towerops.RedisHealthCheckTest do
  use ExUnit.Case, async: false

  import ExUnit.CaptureLog

  alias Towerops.RedisHealthCheck

  describe "wait_for_redis/2" do
    @tag :integration
    test "returns :ok when Redis is available" do
      redis_config = Application.get_env(:towerops, :redis, host: "localhost", port: 6379)

      assert :ok = RedisHealthCheck.wait_for_redis(redis_config, max_attempts: 2, backoff: 100)
    end

    test "returns error after max attempts with unreachable Redis" do
      redis_config = [host: "127.0.0.1", port: 9999]

      # Suppress Redis connection warnings during test
      _logs =
        capture_log(fn ->
          assert {:error, :max_attempts_exceeded} =
                   RedisHealthCheck.wait_for_redis(redis_config,
                     max_attempts: 2,
                     backoff: 10,
                     timeout: 10
                   )
        end)
    end

    test "retries with exponential backoff" do
      redis_config = [host: "127.0.0.1", port: 9999]

      start_time = System.monotonic_time(:millisecond)

      # Suppress Redis connection warnings during test
      _logs =
        capture_log(fn ->
          RedisHealthCheck.wait_for_redis(redis_config,
            max_attempts: 2,
            backoff: 10,
            timeout: 10
          )
        end)

      end_time = System.monotonic_time(:millisecond)
      elapsed = end_time - start_time

      # With backoff of 10ms and 2 attempts, total wait should be at least:
      # attempt 1: fail + wait 10ms
      # attempt 2: fail
      # Total: ~10ms + connection timeouts
      # Just verify some time passed (exponential backoff is working)
      assert elapsed >= 10
    end
  end

  describe "check_health/2" do
    @tag :integration
    test "returns :ok for available Redis" do
      redis_config = Application.get_env(:towerops, :redis, host: "localhost", port: 6379)

      assert :ok = RedisHealthCheck.check_health(redis_config)
    end

    test "returns error for unavailable Redis" do
      redis_config = [host: "127.0.0.1", port: 9999]

      # Suppress Redis connection warnings during test
      _logs =
        capture_log(fn ->
          assert {:error, _reason} = RedisHealthCheck.check_health(redis_config, 10)
        end)
    end

    test "handles malformed Redis config" do
      redis_config = [host: "not-a-valid-hostname-at-all-12345", port: 6379]

      # Suppress Redis connection warnings during test
      _logs =
        capture_log(fn ->
          assert {:error, _reason} = RedisHealthCheck.check_health(redis_config, 10)
        end)
    end

    test "accepts custom timeout" do
      redis_config = [host: "127.0.0.1", port: 9999]

      # Suppress Redis connection warnings during test
      _logs =
        capture_log(fn ->
          result = RedisHealthCheck.check_health(redis_config, 10)
          # Should return error (either immediate connection failure or timeout)
          assert match?({:error, _}, result)
        end)
    end
  end

  describe "concurrent health checks" do
    @tag :integration
    test "handles multiple concurrent health checks" do
      redis_config = Application.get_env(:towerops, :redis, host: "localhost", port: 6379)

      tasks =
        for _ <- 1..5 do
          Task.async(fn -> RedisHealthCheck.check_health(redis_config) end)
        end

      results = Task.await_many(tasks)

      assert Enum.all?(results, &(&1 == :ok))
    end
  end
end
