Skip to main content

lib/alaja/cli/help.ex

defmodule Alaja.CLI.Help do
  @moduledoc """
  Help system for the Alaja CLI.

  Renders help output using Alaja's own components for visually rich,
  consistent terminal output.
  """

  alias Alaja.Components.{Header, Separator, Table}

  # All direct commands mapped to their help module
  @commands %{
    "message" => Alaja.CLI.Commands.Show.Message,
    "header" => Alaja.CLI.Commands.Show.Header,
    "separator" => Alaja.CLI.Commands.Show.Separator,
    "gradient" => Alaja.CLI.Commands.Show.Gradient,
    "table" => Alaja.CLI.Commands.Show.Table,
    "json" => Alaja.CLI.Commands.Show.Json,
    "bar" => Alaja.CLI.Commands.Show.Bar,
    "animated-bar" => Alaja.CLI.Commands.Show.AnimatedBar,
    "breadcrumbs" => Alaja.CLI.Commands.Show.Breadcrumbs,
    "animate" => Alaja.CLI.Commands.Show.Animate,
    "image" => Alaja.CLI.Commands.Show.Image,
    "list" => Alaja.CLI.Commands.Show.List,
    "ask" => Alaja.CLI.Commands.Show.Ask,
    "menu" => Alaja.CLI.Commands.Show.Menu,
    "yesno" => Alaja.CLI.Commands.Show.YesNo,
    "color" => Alaja.CLI.Commands.Color,
    "action" => Alaja.CLI.Commands.Action,
    "config" => Alaja.CLI.Commands.Config
  }

  # ---------------------------------------------------------------------------
  # Summary (alaja with no args)
  # ---------------------------------------------------------------------------

  @doc """
  Renders a compact summary of available commands.
  """
  @spec summary(map()) :: :ok
  def summary(descriptions) do
    Header.print("Alaja",
      subtitle: "Terminal UI & Process Orchestration Framework",
      size: :medium
    )

    IO.puts("")

    rows =
      Enum.map(descriptions, fn {cmd, desc} ->
        [cmd, desc]
      end)

    Table.print(
      headers: ["Command", "Description"],
      rows: rows,
      table_border: :rounded,
      headers_color: :cyan,
      headers_effects: [:bold]
    )

    IO.puts("")

    Separator.print("QUICK REFERENCE", char: "━", width: 50, color: {0, 180, 216})

    Table.print(
      headers: ["Command", "Description"],
      rows: [
        ["alaja --help", "Full reference for all commands"],
        ["alaja <cmd> --help", "Command-specific help"],
        ["alaja --version", "Print version"]
      ],
      table_border: :none,
      padding: 1
    )

    IO.puts("")
    :ok
  end

  # ---------------------------------------------------------------------------
  # Full help (alaja --help)
  # ---------------------------------------------------------------------------

  @doc """
  Renders the complete help for all commands.
  """
  @spec full() :: :ok
  def full do
    Header.print("Alaja CLI", subtitle: "Complete command reference", size: :large)
    IO.puts("")

    global_options()
    IO.puts("")

    typed_messages_section()
    IO.puts("")

    display_commands_section()
    IO.puts("")

    interactive_commands_section()
    IO.puts("")

    color_command_section()
    IO.puts("")

    action_command_section()
    IO.puts("")

    config_command_section()
    IO.puts("")

    Separator.print("MORE HELP", char: "━", width: 80, color: {0, 180, 216})

    Table.print(
      headers: ["Command", "Description"],
      rows: [
        ["alaja <cmd> --help", "Detailed help for any command"]
      ],
      table_border: :none,
      padding: 1
    )

    IO.puts("")
    :ok
  end

  # ---------------------------------------------------------------------------
  # Command-specific help
  # ---------------------------------------------------------------------------

  @doc """
  Renders help for a specific command by delegating to the command module.
  """
  @spec command(String.t()) :: :ok | {:error, :not_found}
  def command(cmd) do
    case Map.fetch(@commands, cmd) do
      {:ok, module} ->
        if function_exported?(module, :help, 0), do: module.help(), else: :ok

      :error ->
        IO.puts(:stderr, "Unknown command: '#{cmd}'")
        {:error, :not_found}
    end
  end

  # ---------------------------------------------------------------------------
  # Sections
  # ---------------------------------------------------------------------------

  defp global_options do
    Separator.print("GLOBAL OPTIONS", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Option", "Description"],
      rows: [
        ["--help, -h", "Show this help"],
        ["--version, -v", "Print version"],
        ["--raw", "Raw positioning mode (message/header/bar/gradient/color)"],
        ["--pos-x N", "X coordinate with --raw"],
        ["--pos-y N", "Y coordinate with --raw"],
        ["--align TYPE", "Alignment: left, center, right"],
        ["--box", "Wrap output in a bordered box (display commands)"],
        ["--box-title TEXT", "Box title (with --box)"],
        ["--box-border TYPE", "Box border style (with --box)"],
        ["--box-color COLOR", "Box border color (with --box)"],
        ["--verbose", "Output raw ANSI instead of rendering"],
        ["--quiet, -q", "Suppress output"],
        ["--stdin", "Read JSON from stdin (action)"]
      ],
      table_border: :none,
      padding: 0
    )
  end

  defp typed_messages_section do
    Separator.print("TYPED MESSAGES", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Command", "Description"],
      rows: [
        ["success", "Success message with green checkmark"],
        ["error", "Error message with red cross"],
        ["warning", "Warning message with yellow triangle"],
        ["info", "Info message with cyan indicator"],
        ["debug", "Debug message with grey indicator"],
        ["notice", "Notice message with blue indicator"],
        ["critical", "Critical message with magenta indicator"],
        ["alert", "Alert message with red indicator"],
        ["emergency", "Emergency message with blinking indicator"],
        ["happy", "Happy message with green indicator"],
        ["sad", "Sad message with blue indicator"]
      ],
      table_border: :none,
      padding: 0
    )

    IO.puts("")
    IO.puts("  Usage: alaja <command> <text>")
    IO.puts("")
  end

  defp display_commands_section do
    Separator.print("DISPLAY COMMANDS", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Command", "Description"],
      rows: [
        ["message", "Custom formatted message with full styling (chunks, colors, effects)"],
        ["header", "Styled header with optional subtitle"],
        ["separator", "Horizontal divider line with optional text"],
        ["gradient", "Gradient-colored text (multi-color support)"],
        ["table", "Rich tables with borders and per-cell styling"],
        ["json", "Pretty-printed JSON with syntax highlighting"],
        ["bar", "Progress bar with customizable appearance"],
        ["animated-bar", "Animated progress bar"],
        ["breadcrumbs", "Navigation path display"],
        ["animate", "Animated spinners and indicators"],
        ["image", "Render images (kitty/iterm2/sixel/ASCII fallback)"],
        ["list", "Styled list with optional header"]
      ],
      table_border: :none,
      padding: 0
    )
  end

  defp interactive_commands_section do
    Separator.print("INTERACTIVE COMMANDS", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Command", "Description"],
      rows: [
        ["ask", "Interactive text input"],
        ["menu", "Interactive selection menu"],
        ["yesno", "Interactive yes/no question"]
      ],
      table_border: :none,
      padding: 0
    )
  end

  defp color_command_section do
    Separator.print("COLOR COMMAND", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Usage", "Description"],
      rows: [
        ["alaja color <color>", "Show color info in all formats"],
        ["alaja color <color> --harmony TYPE", "Generate color harmonies"],
        ["alaja color --colors", "List theme colors"],
        ["alaja color --colors COLS...", "List theme colors with specific columns"],
        ["alaja color --colors all", "List theme colors with every column"],
        ["alaja color <c> --darken N", "Darken by N steps"],
        ["alaja color <c> --lighten N", "Lighten by N steps"],
        ["alaja color <c> --lab", "Include CIELAB values"],
        ["alaja color <c> --xyz", "Include CIE XYZ values"],
        ["alaja color <c> --kelvin", "Include color temperature (K)"],
        ["alaja color <c> --pantone", "Include Pantone approximation"],
        ["alaja color <c> --contrast COLOR", "WCAG contrast ratio and Delta E"]
      ],
      table_border: :none,
      padding: 0
    )

    IO.puts("")

    IO.puts(
      "  Harmony types: triad, complementary, analogous, square, monochromatic, compound, split-complementary"
    )
  end

  defp action_command_section do
    Separator.print("ACTION COMMAND", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Usage", "Description"],
      rows: [
        ["echo JSON | alaja action", "Execute from stdin pipe"],
        ["alaja action --file FILE", "Execute from JSON file"],
        ["alaja action --data JSON", "Execute from inline JSON"],
        ["alaja action --stdin", "Force stdin mode"]
      ],
      table_border: :none,
      padding: 0
    )
  end

  defp config_command_section do
    Separator.print("CONFIG COMMAND", char: "━", width: 80, color: {0, 180, 216})
    IO.puts("")

    Table.print(
      headers: ["Usage", "Description"],
      rows: [
        ["alaja config init", "Initialize config and default themes"],
        ["alaja config get KEY", "Get a configuration value"],
        ["alaja config set KEY VALUE", "Set a configuration value"],
        ["alaja config theme list", "List available themes"],
        ["alaja config theme set NAME", "Set active theme"],
        ["alaja config --show", "Show current configuration"]
      ],
      table_border: :none,
      padding: 0
    )
  end
end