## This Source Code Form is subject to the terms of the Mozilla Public
## License, v. 2.0. If a copy of the MPL was not distributed with this
## file, You can obtain one at https://mozilla.org/MPL/2.0/.
##
## Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  All rights reserved.

defmodule RabbitMQ.CLI.Diagnostics.Commands.ErlangCookieSourcesCommand do
  @behaviour RabbitMQ.CLI.CommandBehaviour

  import RabbitMQ.CLI.Core.ANSI
  import RabbitMQ.CLI.Core.Platform, only: [line_separator: 0]

  use RabbitMQ.CLI.Core.AcceptsDefaultSwitchesAndTimeout
  use RabbitMQ.CLI.Core.MergesNoDefaults
  use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments

  def distribution(_), do: :none

  def run([], opts) do
    switch_cookie = opts[:erlang_cookie]
    home_dir = get_home_dir()
    cookie_file_path = Path.join(home_dir, ".erlang.cookie")

    cookie_file_stat =
      case File.stat(Path.join(home_dir, ".erlang.cookie")) do
        {:error, :enoent} -> nil
        {:ok, value} -> value
      end

    cookie_file_type =
      case cookie_file_stat do
        nil -> nil
        value -> value.type
      end

    cookie_file_access =
      case cookie_file_stat do
        nil -> nil
        value -> value.access
      end

    cookie_file_size =
      case cookie_file_stat do
        nil -> nil
        value -> value.size
      end

    %{
      os_env_cookie_set: System.get_env("RABBITMQ_ERLANG_COOKIE") != nil,
      os_env_cookie_value_length: String.length(System.get_env("RABBITMQ_ERLANG_COOKIE") || ""),
      switch_cookie_set: switch_cookie != nil,
      switch_cookie_value_length: String.length(to_string(switch_cookie)),
      effective_user: System.get_env("USER"),
      home_dir: home_dir,
      cookie_file_path: cookie_file_path,
      cookie_file_exists: File.exists?(cookie_file_path),
      cookie_file_type: cookie_file_type,
      cookie_file_access: cookie_file_access,
      cookie_file_size: cookie_file_size
    }
  end

  def banner([], %{}), do: "Listing Erlang cookie sources used by CLI tools..."

  def output(result, %{formatter: "json"}) do
    {:ok, result}
  end

  def output(result, _opts) do
    cookie_file_lines = [
      "#{bright("Cookie File")}",
      "Effective user: #{result[:effective_user] || "(none)"}",
      "Effective home directory: #{result[:home_dir] || "(none)"}",
      "Cookie file path: #{result[:cookie_file_path]}",
      "Cookie file exists? #{result[:cookie_file_exists]}",
      "Cookie file type: #{result[:cookie_file_type] || "(n/a)"}",
      "Cookie file access: #{result[:cookie_file_access] || "(n/a)"}",
      "Cookie file size: #{result[:cookie_file_size] || "(n/a)"}"
    ]

    switch_lines = [
      "#{line_separator()}#{bright("Cookie CLI Switch")}",
      "--erlang-cookie value set? #{result[:switch_cookie_set]}",
      "--erlang-cookie value length: #{result[:switch_cookie_value_length] || 0}"
    ]

    os_env_lines = [
      "#{line_separator()}#{bright("Env variable ")} #{bright_red("(Deprecated)")}",
      "RABBITMQ_ERLANG_COOKIE value set? #{result[:os_env_cookie_set]}",
      "RABBITMQ_ERLANG_COOKIE value length: #{result[:os_env_cookie_value_length] || 0}"
    ]

    lines = cookie_file_lines ++ switch_lines ++ os_env_lines

    {:ok, Enum.join(lines, line_separator())}
  end

  def help_section(), do: :configuration

  def description() do
    "Display Erlang cookie source (e.g. $HOME/.erlang.cookie file) information useful for troubleshooting"
  end

  def usage, do: "erlang_cookie_sources"

  def formatter(), do: RabbitMQ.CLI.Formatters.String

  #
  # Implementation
  #

  @doc """
  Computes HOME directory path the same way Erlang VM/ei does,
  including taking Windows-specific env variables into account.
  """
  def get_home_dir() do
    homedrive = System.get_env("HOMEDRIVE")
    homepath = System.get_env("HOMEPATH")

    case {homedrive != nil, homepath != nil} do
      {true, true} -> "#{homedrive}#{homepath}"
      _ -> System.get_env("HOME")
    end
  end
end
