defmodule GitHooks.Config.BranchConfig do
  @moduledoc false

  alias GitHooks.Config

  @doc """
  Returns the current branch of user repo
  """
  @spec current_branch() :: String.t()
  def current_branch do
    current_branch_fn =
      Application.get_env(:git_hooks, :current_branch_fn, fn ->
        System.cmd("git", ["rev-parse", "--abbrev-ref", "HEAD"], stderr_to_stdout: true)
      end)

    current_branch_fn.()
    |> Tuple.to_list()
    |> List.first()
    |> String.replace("\n", "")
  end

  @doc """
  Returns if the current branch is allowed to run git hooks based on `branches`
  config.
  """
  @spec current_branch_allowed?(atom) :: boolean()
  def current_branch_allowed?(git_hook_type) do
    branch = current_branch()

    branches_config = branches(git_hook_type)

    whitelist = Keyword.get(branches_config, :whitelist, [])
    blacklist = Keyword.get(branches_config, :blacklist, [])

    valid_branch?(branch, whitelist, blacklist)
  end

  @spec valid_branch?(String.t(), list(String.t()), list(String.t())) :: boolean()
  defp valid_branch?(_, [], []), do: true

  defp valid_branch?(branch, [_ | _] = whitelist, []) do
    regex = whitelist |> Enum.join("|") |> Regex.compile!()

    Regex.match?(regex, branch)
  end

  defp valid_branch?(branch, [], [_ | _] = blacklist) do
    regex = blacklist |> Enum.join("|") |> Regex.compile!()

    not Regex.match?(regex, branch)
  end

  defp valid_branch?(branch, whitelist, blacklist) do
    valid_branch?(branch, whitelist, []) or valid_branch?(branch, [], blacklist)
  end

  @spec branches() :: Keyword.t()
  defp branches do
    Application.get_env(:git_hooks, :branches, [])
  end

  @spec branches(atom) :: Keyword.t()
  defp branches(git_hook_type) do
    git_hook_type
    |> Config.get_git_hook_type_config()
    |> Keyword.get_lazy(:branches, fn -> branches() end)
  end
end
