defmodule Prymn.Agents do
  @moduledoc ~S"""
  Prymn Agents are programs that manage a remote client machine. Prymn backend
  communicates with them using GRPC calls. GRPC connections are started using
  the Prymn.Agents.ConnectionSupervisor and are book-kept using the
  Prymn.Agents.Registry.

  """

  alias Prymn.Agents.Connection
  alias Prymn.Agents.Health

  def start_connection(host_address) do
    spec = {Connection, host_address}

    case DynamicSupervisor.start_child(Prymn.Agents.ConnectionSupervisor, spec) do
      {:ok, _pid} -> :ok
      {:error, {:already_started, _pid}} -> :ok
      {:error, error} -> {:error, error}
    end
  end

  @doc """
  Subscribe to the host's Health using Phoenix.PubSub Broadcasted messages are
  the Health struct:

    %Prymn.Agents.Health{}
  """
  def subscribe_to_health(host_address) do
    :ok = Health.subscribe(host_address)
  end

  @doc """
  Return the last known health status of the Agent, or `nil` if it doesn't
  exist.
  """
  def get_health(host_address) do
    Health.lookup(host_address)
  end

  @doc """
  Get the system's information (CPU, Memory usage, etc.).
  """
  def get_sys_info(host_address) do
    lookup_connection(host_address)
    |> Connection.get_sys_info()
  end

  @doc """
  Perform a system update.

  ## Asynchronous call
  Messages are sent to the caller in the form of the struct:

    %PrymnProto.Prymn.SysUpdateResponse{}
  """
  def sys_update(host_address, dry_run) when is_boolean(dry_run) do
    lookup_connection(host_address)
    |> Connection.sys_update(dry_run)
  end

  defp lookup_connection(host_address) when is_binary(host_address) do
    case Registry.lookup(Prymn.Agents.Registry, host_address) do
      [{pid, _}] -> pid
      [] -> nil
    end
  end
end