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

  # TODO: We should not expose this api, instead wrap every GRPC call in this
  # module GRPC is an "internal implementation detail" (although it probably
  # wont ever change)
  #
  # E.g.
  # def get_sys_info(agent) do
  #   PrymnProto.Prymn.Agent.Stub.get_sys_info(agent.channel, %Google.Protobuf.Empty{})
  # end
  def get_channel(host_address) do
    with [{pid, _}] <- Registry.lookup(Prymn.Agents.Registry, host_address),
         channel when channel != nil <- Connection.get_channel(pid) do
      {:ok, channel}
    else
      _ -> {:error, :not_found}
    end
  end
end