lib/gogs.ex

defmodule Gogs do
  @moduledoc """
  Documentation for `Gogs`.
  This package is an `Elixir` interface to our `Gogs` Server.
  It contains all functions we need to create repositories,
  clone, add data to files, commit, push and diff.
  Some of these functions use `Git` and others use the `REST API`.
  We would _obviously_ prefer if everything was one or the other,
  but sadly, some things cannot be done via `Git` or `REST`
  so we have adopted a "hybrid" approach.

  The functions in this file are defined in the order that we
  are _using_ them. So they tell a story. 
  If you are reading this and prefer to order them alphabetically
  or some other way, please share by opening an issue: 
  github.com/dwyl/gogs/issues
  """
  @access_token Envar.get("GOGS_ACCESS_TOKEN")
  @api_base_url GogsHelpers.api_base_url()
  @httpoison (Application.compile_env(:gogs, :httpoison_mock) &&
                Gogs.HTTPoisonMock) || HTTPoison

  @doc """
  `inject_poison/0` injects a TestDouble of HTTPoison in Test
  so that we don't have duplicate mock in consuming apps.
  see: github.com/dwyl/elixir-auth-google/issues/35
  """
  def inject_poison, do: @httpoison

  @doc """
  make_url/2 constructs the URL based on the supplied git `url` and TCP `port`.
  If the `port` is set it will be a custom Gogs instance.

  ## Examples
    iex> Gogs.make_url("gogs-server.fly.dev", "10022")
    "ssh://git@gogs-server.fly.dev:10022/"
  
    iex> Gogs.make_url("github.com")
    "git@github.com:"

  """
  def make_url(git_url, port \\ 0) do
    if port > 0 do
      "ssh://git@#{git_url}:#{port}/"
    else
      "git@#{git_url}:"
    end
  end


  @doc """
  returns the remote url for cloning
  """
  def remote_url(base_url, org, repo) do
    "#{base_url}#{org}/#{repo}.git"
  end

  @doc """
  `parse_body_response/1` parses the response returned by the Gogs Server
  so your app can use the resulting JSON.
  """
  @spec parse_body_response({atom, String.t()} | {:error, any}) :: {:ok, map} | {:error, any}
  def parse_body_response({:error, err}), do: {:error, err}

  def parse_body_response({:ok, response}) do
    # IO.inspect(response)
    body = Map.get(response, :body)
    # make keys of map atoms for easier access in templates
    if body == nil || byte_size(body) == 0 do
      IO.inspect("response body is nil")
      {:error, :no_body}
    else
      {:ok, str_key_map} = Jason.decode(body)
      {:ok, Useful.atomize_map_keys(str_key_map)}
    end
  end

  @doc """
  `post/2` accepts two arguments: `url` and `params`.
  """
  @spec post(String.t(), map) :: {:ok, map} | {:error, any}
  def post(url, params \\ %{}) do
    # IO.inspect(url, label: url)
    body = Jason.encode!(params)
    headers = [
      {"Accept", "application/json"},
      {"Authorization", "token #{@access_token}"},
      {"Content-Type", "application/json"}
    ]
    inject_poison().post(url, body, headers)
    |> parse_body_response()
  end


  @doc """
  `remote_repo_create/3` accepts two arguments: `org_name`, `repo_name` & `private`.
  It creates a repo on the remote `Gogs` instance as defined 
  by the environment variable `GOGS_URL`.
  For convenience it assumes that you only have _one_ `Gogs` instance.
  If you have more or different requirements, please share!
  """
  def remote_repo_create(org_name, repo_name, private \\ false) do
    url = @api_base_url <> "org/#{org_name}/repos"
    # IO.inspect(url, label: "remote_repo_create url")
    params = %{
      name: repo_name,
      private: private,
      description: repo_name
    }
    post(url, params)
  end

  @doc """
  clone/1 clones a remote git repository based on `git_repo_url`
  returns the path of the _local_ copy of the repository.
  """ 
  def clone(git_repo_url) do
    # IO.inspect("git clone #{git_repo_url}")
    case Git.clone(git_repo_url)  do
      {:ok, %Git.Repository{path: path}} ->
        # IO.inspect(path)
        path
      {:error, %Git.Error{message: _message}} ->
        # IO.inspect("Attempted to clone #{git_repo_url}, got: #{message}")
        get_repo_name_from_url(git_repo_url) |> local_repo_path()
    end
  end

  # Feel free to refactor/simplify this function if you want.
  def get_repo_name_from_url(url) do
    String.split(url, "/") |> List.last() |> String.split(".git") |> List.first()
  end

  def local_repo_path(repo) do
    temp_dir() <> "/" <> repo
  end

  # Made this a function in case we want to 
  defp temp_dir do
    File.cwd!
  end


  # def commit do
    
  # end
end