defmodule MatchmakingEx.CooldownManager do
  @moduledoc """
  A dedicated GenServer for managing the cooldown state of players.
  This follows the Single Responsibility Principle (SRP).
  """
  use GenServer

  @cooldown_duration_in_seconds 30
  @cleanup_interval_in_ms 10_000

  # --- Public API ---

  @doc "Starts the CooldownManager GenServer."
  def start_link(_opts) do
    GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
  end

  @doc "Adds a player to the cooldown list."
  def start_cooldown(player_id) do
    GenServer.cast(__MODULE__, {:start_cooldown, player_id})
  end

  @doc "Checks if a player is on cooldown. Returns {:ok, true, expiration_time} or {:ok, false}."
  def is_on_cooldown?(player_id) do
    GenServer.call(__MODULE__, {:is_on_cooldown?, player_id})
  end

  # --- GenServer Callbacks ---

  @impl true
  def init(cooldowns) do
    # Schedule the first cooldown cleanup.
    Process.send_after(self(), :cleanup_cooldowns, @cleanup_interval_in_ms)
    {:ok, cooldowns}
  end

  @impl true
  def handle_cast({:start_cooldown, player_id}, cooldowns) do
    expiration_time = DateTime.add(DateTime.utc_now(), @cooldown_duration_in_seconds, :second)
    new_cooldowns = Map.put(cooldowns, player_id, expiration_time)
    {:noreply, new_cooldowns}
  end

  @impl true
  def handle_call({:is_on_cooldown?, player_id}, _from, cooldowns) do
    case Map.get(cooldowns, player_id) do
      nil ->
        # Player not found in the cooldown map.
        {:reply, {:ok, false}, cooldowns}

      expiration_time ->
        # Player found, now check if the cooldown has expired.
        if DateTime.compare(DateTime.utc_now(), expiration_time) == :gt do
          # Cooldown has expired.
          new_cooldowns = Map.delete(cooldowns, player_id)
          {:reply, {:ok, false}, new_cooldowns}
        else
          # Cooldown is still active.
          {:reply, {:ok, true, expiration_time}, cooldowns}
        end
    end
  end

  @impl true
  def handle_info(:cleanup_cooldowns, cooldowns) do
    now = DateTime.utc_now()
    active_cooldowns =
      Enum.filter(cooldowns, fn {_player_id, expiration_time} ->
        DateTime.compare(now, expiration_time) == :lt
      end)
      |> Map.new()

    # Schedule the next cleanup.
    Process.send_after(self(), :cleanup_cooldowns, @cleanup_interval_in_ms)
    {:noreply, active_cooldowns}
  end
end
