#!/usr/bin/env bash
set -Eeuo pipefail

source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/dxkit/bootstrap.sh"

# ============================================
# Alias map (commands)
# ============================================

declare -A CMD_ALIASES=(
  [up]=runtime/up
  [down]=runtime/down
  [logs]=runtime/logs
  [list]=runtime/list
  [ls]=runtime/list
  [list-stack]=runtime/list
  [list-containers]=runtime/list
  [exec]=runtime/exec
  [shell]=runtime/shell
  [sh]=runtime/shell
  [bash]=runtime/shell
  [test]=runtime/test

  [net]=network
  [ws]=workspace
)

# ============================================
#                   Modules
# ============================================

load_module env
load_module log
load_module fs
load_module docker
load_module network
load_module artifact

# ============================================
#                   Dispatch
# ============================================

function dx::resolve_alias() {
  local cmd="$1"
  echo "${CMD_ALIASES[$cmd]:-$cmd}"
}

function dx::dispatch() {
  local raw_cmd="${1:-help}"
  shift || true

  local cmd
  cmd="$(dx::resolve_alias "$raw_cmd")"

  # Special built-ins that are not file-based commands
  case "$cmd" in
    help)     dx::help; return ;;
    elevate)  platform::elevate "$@"; return ;;
  esac

  if driver::has_command "$cmd"; then
      driver::run "$cmd" "$@"
      return
  fi

  # Dynamic: load command file and call <cmd>::run
  if load_command "$cmd"; then
    if command::exists "${cmd}"; then
      command::run "${cmd}" "$@"
    else
      log::error "Command file for '${cmd}' loaded but '${cmd}::run' is not defined"
      exit 1
    fi
  else
    log::error "Unknown command: '${raw_cmd}'"
    echo "Run '$(basename "$0") help' to see the available commands." >&2
    exit 1
  fi
}

# ============================================
#                     Help
# ============================================

function dx::help() {
  local console_name
  console_name="$(app::console_name)"

  local framework
  framework="$(app::framework)"

  local console_cmd
  console_cmd="${console_name} | console"

  cat <<HELP
Usage: $(basename "$0") <command> [args...]

Active framework: ${framework}

Commands:
  up                       Start stack
  build                    Build stack
  down                     Stop stack
  logs                     Tail logs
  list | ls                List stack containers
  shell | bash             Enter container shell
  exec <cmd>               Run command inside container
  ${console_cmd}            Run framework console command
  init [env]               Initialize project for environment
  setup                    Build and init in one step
  test                     Run tests
  apache <cmd>             Manage Apache web server
  hosts <cmd>              Manage /etc/hosts entries
  proxy <cmd>              Manage reverse proxy
  network | net <cmd>      Network utilities

Global flags:
  --framework=NAME         Override active framework
  --debug                  Enable shell trace

Examples:
  $(basename "$0") up
  $(basename "$0") build
  $(basename "$0") ${console_name} migrate
  $(basename "$0") init prd
  $(basename "$0") setup
  $(basename "$0") exec ls -la
  $(basename "$0") shell
  $(basename "$0") --framework=laravel build
HELP
}

# ============================================
#                     Main
# ============================================

function main() {
  local args=()
  for arg in "$@"; do
    case "$arg" in
      --framework=*) export APP_FRAMEWORK="${arg#*=}" ;;
      --debug)       set -x ;;
      *) args+=("$arg") ;;
    esac
  done

  load_module app   # app::on_load loads framework/* and registers console alias

  source "$(ctx::dxkit)/drivers/dispatcher.sh"
  driver::load

  env::load_env_files
  dx::dispatch "${args[@]+"${args[@]}"}"
}

main "$@"
