Clone
defmodule Deploy.SSH do
  @moduledoc """
  Shared SSH utilities for deployment mix tasks.

  Provides ssh_exec/2, scp_upload/3, and get_deploy_config/1
  used by Mix.Tasks.Deploy, Deploy.Service, and Deploy.Nginx.
  """

  require Logger

  @doc """
  Load and merge deployment config for the given environment.
  Returns a map with all config keys merged from base + env.
  """
  def get_deploy_config(env) do
    base_config = Application.get_all_env(:deploy)
    env_config = Keyword.get(base_config, env, [])

    if env_config == [] do
      Logger.error("No configuration found for environment: #{env}")
      exit(1)
    end

    app_name = Keyword.get(base_config, :app_name) || (Mix.Project.config()[:app] |> to_string())

    base_config
    |> Keyword.delete(:production)
    |> Keyword.delete(:staging)
    |> Keyword.merge(env_config)
    |> Keyword.put(:env, env)
    |> Keyword.put(:app_name, app_name)
    |> Map.new()
  end

  @doc """
  Execute a command on the remote server via SSH.
  Returns {output, exit_code}.
  """
  def ssh_exec(config, command) do
    port_opt = if config.port && config.port != 22, do: "-p #{config.port}", else: ""

    ssh_command = """
    ssh -T -A -o ConnectTimeout=10 #{port_opt} \
    #{config.user}@#{config.domain} '#{command}'
    """

    Logger.debug("SSH command: #{inspect(ssh_command)}")
    Logger.debug("Remote command: #{inspect(command)}")

    System.cmd("bash", ["-c", ssh_command], stderr_to_stdout: true)
  end

  @doc """
  Upload a local file to the remote server via SCP.
  Returns {output, exit_code}.
  """
  def scp_upload(config, local_file, remote_file) do
    port_opt = if config.port && config.port != 22, do: "-P #{config.port}", else: ""

    scp_command = """
    scp #{port_opt} #{local_file} \
    #{config.user}@#{config.domain}:#{remote_file}
    """

    System.cmd("bash", ["-c", scp_command], stderr_to_stdout: true)
  end
end