defmodule Mix.Tasks.Bolt.Cypher do
  use Mix.Task

  @shortdoc "Execute a Cypher command"
  @recursive true

  @moduledoc """
  Quickly run Cypher commands from a mix task

  ## Command line options

    - `--url`, `-u` - Neo4j server URL
    - `--ssl`, `-s` - use ssl

  The command line options have lower precedence than the options
  specified in your `mix.exs` file, if defined.

  Examples:

      MIX_ENV=test mix bolt.cypher "MATCH (people:Person) RETURN people.name LIMIT 5"

      Output sample:

      "MATCH (people:Person) RETURN people.name as name LIMIT 5"
      [%{"name" => "Keanu Reeves"}, %{"name" => "Carrie-Anne Moss"},
       %{"name" => "Andy Wachowski"}, %{"name" => "Lana Wachowski"},
       %{"name" => "Joel Silver"}]
  """

  alias Bolt.Sips, as: Neo4j

  @doc false
  def run(args) do
    Application.ensure_all_started(:bolt_sips)

    {cli_opts, args, _} = OptionParser.parse(args, aliases: [u: :url, s: :ssl], switches: [])

    options = run_options(cli_opts, Application.get_env(:bolt_sips, Bolt))

    if args == [], do: Mix.raise("Try entering a Cypher command")

    cypher = args |> List.first()

    {:ok, _pid} = Neo4j.start_link(options)

    # display the cypher command
    log_cypher(cypher)

    with {:ok, response} <- Neo4j.query(Bolt.Sips.conn(), cypher) do
      response |> log_response
    else
      {:error, [code: code, message: message]} ->
        "#{inspect(code)} - cannot execute the command, see error above. Details: #{message}"
        |> log_error()

      e ->
        log_error("Unknown error: #{inspect(e)}")
    end
  end

  defp run_options(_, nil) do
    Mix.raise(
      "can't find a valid configuration file, use: MIX_ENV=test mix bolt.cypher \"MATCH...\", for example"
    )
  end

  defp run_options(args, config) do
    Keyword.merge(config, args)
  end

  defp log_cypher(msg), do: Mix.shell().info([:green, "#{inspect(msg)}"])
  defp log_response(msg), do: Mix.shell().info([:yellow, "#{inspect(msg)}"])
  defp log_error(msg), do: Mix.shell().info([:white, "#{msg}"])
end
