#!/usr/bin/env bash
# Terminal Doom via doom-ascii (https://github.com/wojciech-graj/doom-ascii)

BRT_DOOM_DIR="${HOME}/.brt/doom"
BRT_DOOM_BIN="${BRT_DOOM_DIR}/doom-ascii"
BRT_DOOM_SRC="${BRT_DOOM_DIR}/src"
BRT_DOOM_VERSION="0.3.1"
BRT_DOOM_REPO="https://github.com/wojciech-graj/doom-ascii.git"
BRT_FREEDOOM_URL="https://github.com/freedoom/freedoom/releases/download/v0.13.0/freedoom-0.13.0.zip"
BRT_DOOM_IWAD="${BRT_DOOM_DIR}/freedoom1.wad"

brt_doom_scaling() {
  local rows
  rows=$(tput lines 2>/dev/null || echo 24)
  if (( rows >= 40 )); then
    echo 2
  elif (( rows >= 28 )); then
    echo 3
  else
    echo 4
  fi
}

brt_doom_write_config() {
  local cfg="${BRT_DOOM_DIR}/.default.cfg"
  cat > "$cfg" <<'EOF'
# brt -doom controls (DOS scancodes; see chocolate-doom default.cfg)
use_mouse                     1
mouseb_fire                   0
mouseb_strafe                 0
mouseb_forward                0
mouseb_speed                  0
grabmouse                     1
mouse_sensitivity             7

# Move: WASD
key_up                        17
key_down                      31
key_strafeleft                30
key_straferight               32

# Look / turn: arrow keys
key_left                      75
key_right                     77

# Space = use (classic Doom has no jump)
key_use                       57

# Right Shift = fire
key_fire                      54

# Run on ]
key_speed                     27
EOF
}

brt_doom_ensure_wad() {
  local zip tmpdir

  if [[ -f "$BRT_DOOM_IWAD" ]]; then
    return 0
  fi

  brt_require curl
  brt_require unzip

  brt_info "Downloading Freedoom WAD (first run only)..."
  zip=$(mktemp "${TMPDIR:-/tmp}/brt-freedoom.XXXXXX.zip")
  tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/brt-freedoom.XXXXXX")

  if ! curl -fsSL --progress-bar "$BRT_FREEDOOM_URL" -o "$zip"; then
    rm -f "$zip"
    rm -rf "$tmpdir"
    brt_error "Failed to download Freedoom from ${BRT_FREEDOOM_URL}"
    brt_info "Place doom1.wad or freedoom1.wad in ${BRT_DOOM_DIR}/"
    return 1
  fi

  unzip -qq -o "$zip" -d "$tmpdir" || {
    rm -f "$zip"
    rm -rf "$tmpdir"
    brt_error "Failed to extract Freedoom archive"
    return 1
  }

  local wad
  wad=$(find "$tmpdir" -name 'freedoom1.wad' -print -quit)
  if [[ -z "$wad" ]]; then
    rm -f "$zip"
    rm -rf "$tmpdir"
    brt_error "freedoom1.wad not found in archive"
    return 1
  fi

  cp "$wad" "$BRT_DOOM_IWAD"
  rm -f "$zip"
  rm -rf "$tmpdir"
  brt_ok "Installed ${BRT_DOOM_IWAD}"
}

brt_doom_find_wad() {
  local wad="${1:-}"

  if [[ -n "$wad" && -f "$wad" ]]; then
    case "$wad" in
      ~/*) wad="${HOME}/${wad#~/}" ;;
      ~) wad="$HOME" ;;
    esac
    if command -v realpath &>/dev/null; then
      realpath "$wad"
    else
      (cd "$(dirname "$wad")" && printf '%s/%s\n' "$(pwd)" "$(basename "$wad")")
    fi
    return 0
  fi

  if [[ -f "$BRT_DOOM_IWAD" ]]; then
    printf '%s\n' "$BRT_DOOM_IWAD"
    return 0
  fi

  for wad in "${HOME}/.brt/doom/doom1.wad" "${HOME}/.brt/doom/DOOM1.WAD" \
    "${HOME}/.brt/doom/freedoom1.wad"; do
    if [[ -f "$wad" ]]; then
      printf '%s\n' "$wad"
      return 0
    fi
  done

  return 1
}

brt_doom_ensure_binary() {
  if [[ -x "$BRT_DOOM_BIN" ]]; then
    return 0
  fi

  brt_require git
  brt_require make
  brt_require cc

  mkdir -p "$BRT_DOOM_DIR"

  if [[ ! -d "${BRT_DOOM_SRC}/.git" ]]; then
    brt_info "Fetching doom-ascii ${BRT_DOOM_VERSION} (first run only)..."
    git clone --depth 1 --branch "${BRT_DOOM_VERSION}" "$BRT_DOOM_REPO" "$BRT_DOOM_SRC" \
      || {
        brt_error "Failed to clone doom-ascii"
        return 1
      }
  fi

  brt_info "Building doom-ascii..."
  if ! make -C "$BRT_DOOM_SRC" -j"$(sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 2)"; then
    brt_error "Failed to build doom-ascii (need Xcode CLT or gcc)"
    return 1
  fi

  local built=""
  for built in \
    "${BRT_DOOM_SRC}/game/doom-ascii" \
    "${BRT_DOOM_SRC}/_unix/game/doom-ascii" \
    "${BRT_DOOM_SRC}/_unix/obj/doom-ascii"; do
    if [[ -f "$built" ]]; then
      cp "$built" "$BRT_DOOM_BIN"
      chmod +x "$BRT_DOOM_BIN"
      brt_ok "Built ${BRT_DOOM_BIN}"
      return 0
    fi
  done

  brt_error "Build finished but doom-ascii binary is missing"
  return 1
}

brt_doom_term_restore() {
  [[ -w /dev/tty ]] || return 0
  printf '\033[?25h\033[0m\033[r' >/dev/tty 2>/dev/null || true
  stty sane </dev/tty 2>/dev/null || true
}

brt_doom_on_exit() {
  brt_doom_term_restore
}

brt_doom() {
  local wad_arg="" scaling rc=0
  local -a extra_args=()

  while [[ $# -gt 0 ]]; do
    case "$1" in
      -h|--help)
        cat <<EOF
brt -doom — play Doom in the terminal

Controls:
  WASD              Move (forward / back / strafe)
  Mouse move        Turn (if terminal/backend supports mouse reporting)
  Left click        Fire (if terminal/backend supports mouse reporting)
  Arrow keys        Turn fallback
  Space             Use doors and switches
  Right Shift       Fire fallback
  ]                 Run
  Esc               Menu
  Ctrl+C            Quit

Options:
  --wad <file>      Use a specific WAD (default: Freedoom, auto-downloaded)
  --scaling <N>     Display scale 2–4 (smaller = larger; default: auto)

Requires: git, make, and a C compiler on first run.
EOF
        return 0
        ;;
      --wad)
        wad_arg="${2:-}"
        [[ -n "$wad_arg" ]] || { brt_error "--wad requires a path"; exit 1; }
        shift 2
        ;;
      --scaling)
        extra_args+=("-scaling" "${2:-}")
        [[ -n "${2:-}" ]] || { brt_error "--scaling requires a number"; exit 1; }
        shift 2
        ;;
      *)
        if [[ -z "$wad_arg" && -f "$1" ]]; then
          wad_arg="$1"
          shift
        else
          brt_error "Unknown option: $1"
          brt_info "Run: brt -doom --help"
          exit 1
        fi
        ;;
    esac
  done

  brt_doom_ensure_binary || exit 1
  brt_doom_write_config

  local iwad
  if ! iwad=$(brt_doom_find_wad "$wad_arg"); then
    brt_doom_ensure_wad || exit 1
    iwad=$(brt_doom_find_wad "") || {
      brt_error "No WAD file found"
      exit 1
    }
  fi

  local scaling_flag
  scaling_flag=$(brt_doom_scaling)
  if ((${#extra_args[@]} == 0)); then
    extra_args=("-scaling" "$scaling_flag")
  fi
  extra_args+=("-chars" "block" "-kpsmooth" "8")

  brt_info "WAD: ${iwad}"
  brt_info "Renderer: unicode block cells (-chars block)"
  brt_info "Controls: mouse move/click (when supported) · arrows/Right Shift fallback · WASD move · Ctrl+C quit"

  trap 'brt_doom_on_exit' EXIT INT TERM

  set +e
  (
    cd "$BRT_DOOM_DIR" || exit 1
    exec "$BRT_DOOM_BIN" \
      -iwad "$iwad" \
      "${extra_args[@]}"
  )
  rc=$?
  set -e

  brt_doom_term_restore

  if (( rc == 0 || rc == 130 || rc == 143 )); then
    return 0
  fi
  brt_error "Doom exited with code ${rc}"
  return "$rc"
}
