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

# ---------------------------------------------------------------------------
# Argument parsing — strip --img <value> from args before mode dispatch
# ---------------------------------------------------------------------------
IMG2NUM_IMAGE_FLAG=""
IMG2NUM_IMAGE_SOURCE_SET=0
FILTERED_ARGS=()
while [ $# -gt 0 ]; do
  case "$1" in
    --img|--dh-img|--ghcr-img)
      if [ "$IMG2NUM_IMAGE_SOURCE_SET" -eq 1 ]; then
        echo "Error: Only one of --img, --dh-img, or --ghcr-img may be used." >&2
        exit 1
      fi
      IMG2NUM_IMAGE_SOURCE_SET=1

      flag="$1"
      shift

      if [ $# -eq 0 ] || [ -z "$1" ]; then
        echo "Error: $flag requires a tag argument." >&2
        exit 1
      fi
      if [[ "$flag" == "--dh-img" || "$flag" == "--ghcr-img" ]] && [[ "$1" == *:* ]]; then
        echo "Error: $flag expects a tag, not a full image (no ':'). Use --img instead." >&2
        exit 1
      fi

      case "$flag" in
        --img)      IMG2NUM_IMAGE_FLAG="$1" ;;
        --dh-img)   IMG2NUM_IMAGE_FLAG="ryanmillard/img2num-dev:$1" ;;
        --ghcr-img) IMG2NUM_IMAGE_FLAG="ghcr.io/ryan-millard/img2num-dev:$1" ;;
      esac
      ;;
    *) FILTERED_ARGS+=("$1") ;;
  esac
  shift
done
set -- "${FILTERED_ARGS[@]+"${FILTERED_ARGS[@]}"}"

MODE="${1:-}"
shift || true

# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
IMG2NUM_DEFAULT_IMAGE="ryanmillard/img2num-dev:dev"
IMG2NUM_STATE_FILE="$(dirname "$0")/.img2num-state"

# ---------------------------------------------------------------------------
# State helpers
# ---------------------------------------------------------------------------

save_state() {
  local image="$1"
  if [ -f "$IMG2NUM_STATE_FILE" ] && grep -q '^IMAGE=' "$IMG2NUM_STATE_FILE"; then
    local tmp
    tmp="$(mktemp)"
    trap 'rm -f "$tmp"' EXIT
    awk -v img="$image" 'BEGIN{done=0} /^IMAGE=/ && !done {print "IMAGE=" img; done=1; next} {print}' \
      "$IMG2NUM_STATE_FILE" > "$tmp" && mv "$tmp" "$IMG2NUM_STATE_FILE"
    trap - EXIT
  else
    printf 'IMAGE=%s\n' "$image" >> "$IMG2NUM_STATE_FILE"
  fi
}

# Returns the image to use, in priority order:
#   1. --img, --ghcr-img, --dh-img flag
#   2. IMG2NUM_IMAGE env var (caller-supplied override)
#   3. State file  (persisted from last `up`)
#   4. Hardcoded default
load_image() {
  if [ -n "$IMG2NUM_IMAGE_FLAG" ]; then
    printf '%s\n' "$IMG2NUM_IMAGE_FLAG"
    return
  fi
  if [ -n "${IMG2NUM_IMAGE:-}" ]; then
    printf '%s\n' "$IMG2NUM_IMAGE"
    return
  fi
  if [ -f "$IMG2NUM_STATE_FILE" ]; then
    local line val
    line="$(grep -m1 '^IMAGE=' "$IMG2NUM_STATE_FILE" | tr -d '\r')"
    val="${line#IMAGE=}"
    if [ -n "$val" ]; then
      printf '%s\n' "$val"
      return
    fi
  fi
  printf '%s\n' "$IMG2NUM_DEFAULT_IMAGE"
}

# ---------------------------------------------------------------------------
# Container helpers
# ---------------------------------------------------------------------------

# Run a command inside the dev container, using the resolved image.
# The image is exported so docker-compose.yml can reference ${IMG2NUM_IMAGE}.
run_in_container() {
  local image
  image="$(load_image)"
  save_state "$image"
  export IMG2NUM_IMAGE="$image"
  docker compose up -d dev
  if [ -z "$(docker compose ps -q --status running dev 2>/dev/null)" ]; then
    echo "Error: container 'dev' is not running." >&2
    exit 1
  fi
  # No TTY in GitHub Actions
  docker compose exec ${CI:+-T} dev "$@"
}

# ---------------------------------------------------------------------------
# Main command dispatch
# ---------------------------------------------------------------------------
# Ensure that Docker is available for the relevant commands.
case "$MODE" in
  stop|restart|down|purge|destroy|logs)
    command -v docker >/dev/null 2>&1 || {
      echo "Error: docker is unavailable (not installed, not running or not in PATH)." >&2
      exit 1
    }
    ;;
esac
case "$MODE" in
  # Arbitrary one-off commands
  # Run command in shell, then leave
  run|exec)
    if [ $# -gt 0 ]; then
      run_in_container "$@"
    else
      echo "Error: run/exec requires a command." >&2
      exit 1
    fi
    ;;

  # Open a shell in the container
  sh|shell|bash|term|terminal)
    run_in_container bash
    ;;

  # Docker management shortcuts
  stop)    docker compose stop ;;
  restart) docker compose restart ;;
  down)    docker compose down ;;

  purge|destroy)
    docker compose down --volumes --remove-orphans
    if [ "$MODE" = "destroy" ]; then
      IMAGE_TO_REMOVE="$(load_image)"
      echo "Removing $IMAGE_TO_REMOVE in 5s..."
      sleep 5
      docker image inspect "$IMAGE_TO_REMOVE" >/dev/null 2>&1 && \
      docker rmi "$IMAGE_TO_REMOVE" 2>/dev/null || true
      # Clear the persisted image so the next `up` falls back to the default
      if [ -f "$IMG2NUM_STATE_FILE" ]; then
        tmp="$(mktemp)"
        trap 'rm -f "$tmp"' EXIT
        sed 's/^IMAGE=.*/IMAGE=/' "$IMG2NUM_STATE_FILE" > "$tmp" && mv "$tmp" "$IMG2NUM_STATE_FILE"
        trap - EXIT
      else
        printf 'IMAGE=\n' >> "$IMG2NUM_STATE_FILE"
      fi
    fi
    ;;

  # Tail logs
  logs) docker compose logs -f ;;

  last-img|last-image)
    load_image
    ;;

  # Fallback usage
  -h|--help|*)
    EXIT_CODE=0
    if [ "$MODE" != "-h" ] && [ "$MODE" != "--help" ]; then
      EXIT_CODE=1
      echo "Unknown command used."
      echo
    fi
    cat <<EOF
Usage:
  ./img2num [--img <image:tag>] <command>

Commands:
    run|exec <args>     Run arbitrary one-off command inside the container.     [--img, --dh-img, --ghcr-img]
    sh|shell|bash       Opens bash terminal in Docker container.                [--img, --dh-img, --ghcr-img]

    stop                Stops running Docker container (keeps containers, volumes & networks).
    restart             Restarts running Docker container.
    down                Stops running Docker container (keeps volumes).
    purge               Stops running Docker container (removes everything, including orphans).
    destroy             Same as purge, but deletes Docker image.                [--img, --dh-img, --ghcr-img]
    logs                Displays any relevant Docker logs.

    last-img|last-image Displays the resolved Docker image (based on current config).
    -h|--help           Displays this message.

Flags:
  --img                 Use a specific Docker image.
                          E.g.: ./img2num sh --img ryanmillard/img2num-dev:dev
  --dh-img              Docker Hub shorthand for --img. Prefixes value with ryanmillard/img2num-dev:
                          E.g.: ./img2num sh --dh-img dev
                            Resolves Docker image to ryanmillard/img2num-dev:dev
  --ghcr-img            GitHub shorthand for --img. Prefixes value with ghcr.io/ryan-millard/img2num-dev:
                          E.g.: ./img2num sh --ghcr-img dev
                           Resolves Docker image to ghcr.io/ryan-millard/img2num-dev:dev

Image Resolution (highest priority first):
  Applies to: run, exec, sh/shell/bash, destroy
  1. Image flags (--img, --dh-img, --ghcr-img)
  2. IMG2NUM_IMAGE env var
  3. Last image used with this script (in .img2num-state file)
  4. Default: $IMG2NUM_DEFAULT_IMAGE
EOF
    exit $EXIT_CODE
    ;;
esac

