defmodule Venomous.PetSnakeManager do
  @moduledoc "SnakeManager but for pets..."
  use GenServer
  require Logger
  alias Venomous.PetSnakeSupervisor

  def start_link(args) do
    GenServer.start_link(__MODULE__, args, name: __MODULE__)
  end

  def init(state) do
    Logger.info("Started Pet Snake Manager")

    {:ok, state}
  end

  def handle_info({:reject_pet, name, style}, state) do
    case state.table |> :ets.lookup(name) do
      [] ->
        :ok

      [{_name, pid, pypid, os_pid}] ->
        :python.stop(pypid)
        DynamicSupervisor.terminate_child(PetSnakeSupervisor, pid)
        if style == :brutal, do: System.cmd("kill", ["-9", "#{os_pid}"])
        :ets.delete(state.table, name)
    end

    {:noreply, state}
  end

  defp adopt_snake({:error, message}, _name, _table), do: {:error, message}

  defp adopt_snake({:ok, pid}, name, table) do
    worker = GenServer.call(pid, :get_pypid)
    :ets.insert(table, {name, worker.pid, worker.pypid, worker.os_pid})
    {:ok, name}
  end

  defp adopt_snake(true, _name, _opts, _table), do: {:error, :exists}

  defp adopt_snake(false, name, opts, table) do
    PetSnakeSupervisor.deploy_snake_pet(opts) |> adopt_snake(name, table)
  end

  def handle_call({:adopt_snake, name, opts}, _from, state) do
    exists? = state.table |> :ets.lookup(name) |> Kernel.!=([])
    {:reply, adopt_snake(exists?, name, opts, state.table), state}
  end

  def handle_call({:get_snake, name}, _from, state) do
    snake =
      case state.table |> :ets.lookup(name) do
        [] ->
          {:error, :not_found}

        [{_name, pid, _pypid, _os_pid}] ->
          pid
      end

    {:reply, snake, state}
  end
end
