defmodule Mobilizon.PythonWorker do
  @moduledoc """
  Genserver to handle an instance of Python handling the calls to `Mobilizon.PythonPort`.
  """

  use GenServer
  use Export.Python

  alias Mobilizon.PythonPort

  @spec start_link(any) :: :ignore | {:error, any} | {:ok, pid}
  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  @spec init(any) :: {:ok, %{python_pid: pid}}
  def init(_) do
    path = Path.join([:code.priv_dir(:mobilizon), "python"])
    pid = PythonPort.python_instance(path)

    {:ok, %{python_pid: pid}}
  end

  def terminate(_reason, %{python_pid: pid}) do
    Python.stop(pid)
  end

  @spec generate_pdf(String.t()) :: any
  def generate_pdf(html) do
    GenServer.call(__MODULE__, %{html: html, format: :pdf})
  end

  @spec generate_ods(String.t()) :: any
  def generate_ods(data) do
    GenServer.call(__MODULE__, %{data: data, format: :ods})
  end

  @spec has_module(String.t()) :: any
  def has_module(module) do
    GenServer.call(__MODULE__, %{module: module})
  end

  @spec handle_call(
          %{html: String.t(), format: :pdf} | %{data: String.t(), format: :ods},
          any(),
          map()
        ) :: {:reply, String.t(), map()}
  def handle_call(%{html: html, format: :pdf}, _from, %{python_pid: pid} = state) do
    res = PythonPort.call_python(pid, "pdf", "generate", [html])

    {:reply, res, state}
  end

  def handle_call(%{data: data, format: :ods}, _from, %{python_pid: pid} = state) do
    res = PythonPort.call_python(pid, "ods", "generate", [data])

    {:reply, res, state}
  end

  def handle_call(%{module: module}, _from, %{python_pid: pid} = state) do
    res = PythonPort.call_python(pid, "module", "has_package", [module])

    {:reply, res, state}
  end
end