#!/usr/bin/env bash
set -euo pipefail
unset CDPATH

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT_DIR="$ROOT_DIR/scripts"

run_step() {
  local name="$1"
  shift
  echo "==> Running: $name"
  if "$@"; then
    echo "OK: $name"
  else
    echo "FAIL: $name"
    return 1
  fi
}

run_create_dir() { bash "$SCRIPT_DIR/create-dir.sh"; }
run_new_docs() { bash "$SCRIPT_DIR/new-docs.sh"; }
run_new_app() { bash "$SCRIPT_DIR/new-app.sh"; }

check_config() {
  local missing=0
  local p
  local paths=(
    "common"
    "common/php"
    "common/js"
    "common/css"
    "common/data"
    "common/data/config"
    "common/data/images"
    "common/pages"
    "common/docs"
    "common/templates"
    "sys-apps"
    "sys-apps/app-sys"
    "sys-apps/app-sys/php"
    "sys-apps/app-sys/js"
    "sys-apps/app-sys/css"
    "sys-apps/app-sys/data"
    "sys-apps/app-sys/pages"
    "defaults"
    "defaults/config"
    "defaults/docs"
    "defaults/templates"
    "defaults/templates/tmpl-sys"
    "defaults/templates/tmpl-games"
    "apps"
    "scripts"
    "scripts/create-dir.sh"
    "scripts/new-docs.sh"
    "scripts/new-app.sh"
    "scripts/runall.sh"
  )

  for p in "${paths[@]}"; do
    if [[ -e "$ROOT_DIR/$p" ]]; then
      echo "OK: $p"
    else
      echo "MISSING: $p"
      missing=1
    fi
  done

  return "$missing"
}

check_naming() {
  local bad=0
  local path base
  while IFS= read -r path; do
    [[ -z "$path" ]] && continue
    base="$(basename "$path")"
    [[ "$base" == ".DS_Store" ]] && continue
    if [[ "$base" =~ [A-Z_] || "$base" =~ [[:space:]] ]]; then
      echo "BAD NAME: $path"
      bad=1
    fi
  done < <(find "$ROOT_DIR" -path "$ROOT_DIR/.git" -prune -o -name '.DS_Store' -prune -o -print)
  return "$bad"
}

fix_naming() {
  local bad=0
  local path base dir new
  while IFS= read -r path; do
    [[ -z "$path" ]] && continue
    base="$(basename "$path")"
    dir="$(dirname "$path")"
    [[ "$base" == ".DS_Store" ]] && continue
    new="$(printf '%s' "$base" | tr '[:upper:]_' '[:lower:]-' | tr ' ' '-')"
    if [[ "$base" != "$new" ]]; then
      if [[ -e "$dir/$new" ]]; then
        echo "SKIP COLLISION: $path -> $dir/$new already exists"
        bad=1
        continue
      fi
      mv -- "$path" "$dir/$new"
      echo "RENAMED: $path -> $dir/$new"
    fi
  done < <(find "$ROOT_DIR" -path "$ROOT_DIR/.git" -prune -o -name '.DS_Store' -prune -o -depth -print)
  return "$bad"
}

show_menu() {
  printf '%-20s %-20s %-20s\n' "a) run all" "c) create-dir" "d) new-docs"
  printf '%-20s %-20s %-20s\n' "n) new-app" "k) check config" "p) check naming"
  printf '%-20s %-20s %-20s\n' "f) fix naming" "i) install" "m) show menu"
  printf '%-20s %-20s %-20s\n' "q) quit" "" ""
}

menu_loop() {
  while true; do
    echo
    echo "Runall menu"
    echo "-----------"
    show_menu
    echo
    read -r -n 1 -p "Choice [a/c/d/n/k/p/f/i/m/q]: " REPLY
    echo
    choice="$(printf '%s' "$REPLY" | tr '[:upper:]' '[:lower:]')"
    case "$choice" in
      a) run_step "create-dir" run_create_dir; run_step "new-docs" run_new_docs; run_step "new-app" run_new_app ;;
      c) run_step "create-dir" run_create_dir ;;
      d) run_step "new-docs" run_new_docs ;;
      n) run_step "new-app" run_new_app ;;
      k) if check_config; then echo "OK: config check"; else echo "FAIL: config check"; fi ;;
      p) if check_naming; then echo "OK: naming check"; else echo "FAIL: naming check"; fi ;;
      f) if fix_naming; then echo "OK: naming fix"; else echo "FAIL: naming fix"; fi ;;
      i) run_step "create-dir" run_create_dir; run_step "new-docs" run_new_docs; run_step "new-app" run_new_app; if fix_naming; then echo "OK: naming fix"; else echo "FAIL: naming fix"; fi ;;
      m) continue ;;
      q) break ;;
      *) echo "Invalid choice: $REPLY" ;;
    esac
  done
}

usage() {
  cat <<EOF
Usage: $(basename "$0") [options]

Options:
  -a, --all            Run create-dir, new-docs, and new-app
  -c, --create-dir     Run create-dir.sh only
  -d, --new-docs       Run new-docs.sh only
  -n, --new-app        Run new-app.sh only
  -k, --check-config   Check expected directories/files
  -p, --check-naming   Check lowercase/hyphen naming
  -f, --fix-naming     Rename names to lowercase/hyphen standard
  -i, --install        Run create-dir, new-docs, new-app, then fix naming
  -m, --menu           Show interactive menu
  -h, --help           Show this help
EOF
}

mode="menu"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -a|--all) mode="all" ;;
    -c|--create-dir) mode="create-dir" ;;
    -d|--new-docs) mode="new-docs" ;;
    -n|--new-app) mode="new-app" ;;
    -k|--check-config) mode="check-config" ;;
    -p|--check-naming) mode="check-naming" ;;
    -f|--fix-naming) mode="fix-naming" ;;
    -i|--install) mode="install" ;;
    -m|--menu) mode="menu" ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
  esac
  shift
done

case "$mode" in
  all) run_step "create-dir" run_create_dir; run_step "new-docs" run_new_docs; run_step "new-app" run_new_app ;;
  create-dir) run_step "create-dir" run_create_dir ;;
  new-docs) run_step "new-docs" run_new_docs ;;
  new-app) run_step "new-app" run_new_app ;;
  check-config) if check_config; then echo "OK: config check"; else echo "FAIL: config check"; exit 1; fi ;;
  check-naming) if check_naming; then echo "OK: naming check"; else echo "FAIL: naming check"; exit 1; fi ;;
  fix-naming) if fix_naming; then echo "OK: naming fix"; else echo "FAIL: naming fix"; exit 1; fi ;;
  install) run_step "create-dir" run_create_dir; run_step "new-docs" run_new_docs; run_step "new-app" run_new_app; if fix_naming; then echo "OK: naming fix"; else echo "FAIL: naming fix"; exit 1; fi ;;
  menu) menu_loop ;;
esac
