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

if [[ -z "${BASH_VERSION:-}" ]]; then
  echo "Error: run this script with bash (example: bash deploy_synology.sh)." >&2
  exit 1
fi

# ManeshTrader quick deploy helper for Synology Docker host.
# Defaults are set for the target provided by the user.

ENV_FILE=".env.deploy_synology"
if [[ -f "$ENV_FILE" ]]; then
  # shellcheck disable=SC1090
  set -a; source "$ENV_FILE"; set +a
fi

REMOTE_USER="${REMOTE_USER:-mbrucedogs}"
REMOTE_HOST="${REMOTE_HOST:-192.168.1.128}"
REMOTE_PORT="${REMOTE_PORT:-25}"
REMOTE_BASE="${REMOTE_BASE:-/volume1/docker/maneshtrader}"
LOCAL_BASE="${LOCAL_BASE:-web/src}"
SYNO_PASSWORD="${SYNO_PASSWORD:-}"
CONTAINER_NAME="${CONTAINER_NAME:-}"
SUDO_PASSWORD="${SUDO_PASSWORD:-${SYNO_PASSWORD:-}}"
SUDO_MODE="${SUDO_MODE:-auto}"   # auto|always|never
SSH_PASS_WARNING_SHOWN="0"

MODE="bind"             # bind: upload + restart; image: upload + rebuild
NO_RESTART="0"
DRY_RUN="0"

DEFAULT_FILES=(
  "web/src/web_core/ui/help_content.py"
  "web/src/PRD.md"
  "web/src/ONBOARDING.md"
)

FILES=("${DEFAULT_FILES[@]}")

usage() {
  cat <<'EOF'
Usage:
  ./deploy_synology.sh [options]

Options:
  --mode bind|image       Deploy mode (default: bind)
  --files "a b c"         Space-separated file list to upload
  --recent-minutes N      Upload files under web/src modified in last N minutes
  --git-hours N           Upload files changed in last N hours (git history + working tree)
  --env-file PATH         Load environment variables from file (default: .env.deploy_synology if present)
  --sudo-mode MODE        Docker privilege mode: auto|always|never (default: auto)
  --no-restart            Upload only; skip remote docker restart/rebuild
  --dry-run               Print actions but do not execute
  -h, --help              Show help

Environment overrides:
  REMOTE_USER, REMOTE_HOST, REMOTE_PORT, REMOTE_BASE, LOCAL_BASE, SYNO_PASSWORD, CONTAINER_NAME,
  SUDO_PASSWORD, SUDO_MODE

Examples:
  ./deploy_synology.sh
  ./deploy_synology.sh --mode image
  ./deploy_synology.sh --recent-minutes 120
  ./deploy_synology.sh --git-hours 2
  ./deploy_synology.sh --env-file .env.deploy_synology --git-hours 2
  ./deploy_synology.sh --git-hours 2 --sudo-mode always
  ./deploy_synology.sh --files "web/src/web_core/ui/help_content.py"
EOF
}

run_cmd() {
  if [[ "$DRY_RUN" == "1" ]]; then
    printf '[dry-run] %s\n' "$*"
  else
    eval "$@"
  fi
}

build_ssh_cmd() {
  if [[ -n "${SYNO_PASSWORD:-}" ]]; then
    if ! command -v sshpass >/dev/null 2>&1; then
      if [[ "$SSH_PASS_WARNING_SHOWN" == "0" ]]; then
        echo "Warning: SYNO_PASSWORD is set but sshpass is not installed; falling back to interactive ssh/scp prompts." >&2
        SSH_PASS_WARNING_SHOWN="1"
      fi
      printf "ssh -p '%s' '%s@%s'" "${REMOTE_PORT}" "${REMOTE_USER}" "${REMOTE_HOST}"
      return
    fi
    printf "SSHPASS='%s' sshpass -e ssh -o StrictHostKeyChecking=accept-new -p '%s' '%s@%s'" \
      "${SYNO_PASSWORD}" "${REMOTE_PORT}" "${REMOTE_USER}" "${REMOTE_HOST}"
  else
    printf "ssh -p '%s' '%s@%s'" "${REMOTE_PORT}" "${REMOTE_USER}" "${REMOTE_HOST}"
  fi
}

build_scp_cmd() {
  if [[ -n "${SYNO_PASSWORD:-}" ]]; then
    if ! command -v sshpass >/dev/null 2>&1; then
      if [[ "$SSH_PASS_WARNING_SHOWN" == "0" ]]; then
        echo "Warning: SYNO_PASSWORD is set but sshpass is not installed; falling back to interactive ssh/scp prompts." >&2
        SSH_PASS_WARNING_SHOWN="1"
      fi
      printf "scp -O -P '%s'" "${REMOTE_PORT}"
      return
    fi
    printf "SSHPASS='%s' sshpass -e scp -O -o StrictHostKeyChecking=accept-new -P '%s'" \
      "${SYNO_PASSWORD}" "${REMOTE_PORT}"
  else
    printf "scp -O -P '%s'" "${REMOTE_PORT}"
  fi
}

to_remote_rel_path() {
  local file="$1"
  local prefix="${LOCAL_BASE%/}/"
  if [[ "$file" == "$prefix"* ]]; then
    printf "%s" "${file#$prefix}"
  else
    printf "%s" "$file"
  fi
}

collect_git_hours_files() {
  local hours="$1"
  local base_commit
  local combined

  if ! command -v git >/dev/null 2>&1; then
    echo "Error: git is required for --git-hours." >&2
    exit 1
  fi
  if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    echo "Error: --git-hours must be run from inside a git repository." >&2
    exit 1
  fi

  base_commit="$(git rev-list -n 1 --before="${hours} hours ago" HEAD 2>/dev/null || true)"

  combined="$(
    {
      if [[ -n "$base_commit" ]]; then
        git diff --name-only --diff-filter=ACMRTUXB "${base_commit}..HEAD" -- web/src
      fi
      git diff --name-only -- web/src
      git diff --cached --name-only -- web/src
      git ls-files -m -o --exclude-standard -- web/src
    } | sed '/^$/d' | sort -u
  )"

  FILES=()
  while IFS= read -r candidate; do
    [[ -z "$candidate" ]] && continue
    FILES+=("$candidate")
  done <<EOF
$combined
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --mode)
      MODE="${2:-}"
      shift 2
      ;;
    --env-file)
      ENV_FILE="${2:-}"
      if [[ ! -f "$ENV_FILE" ]]; then
        echo "Error: env file not found: $ENV_FILE" >&2
        exit 1
      fi
      # shellcheck disable=SC1090
      set -a; source "$ENV_FILE"; set +a
      REMOTE_USER="${REMOTE_USER:-mbrucedogs}"
      REMOTE_HOST="${REMOTE_HOST:-192.168.1.128}"
      REMOTE_PORT="${REMOTE_PORT:-25}"
      REMOTE_BASE="${REMOTE_BASE:-/volume1/docker/maneshtrader}"
      LOCAL_BASE="${LOCAL_BASE:-web/src}"
      SYNO_PASSWORD="${SYNO_PASSWORD:-}"
      CONTAINER_NAME="${CONTAINER_NAME:-}"
      SUDO_PASSWORD="${SUDO_PASSWORD:-${SYNO_PASSWORD:-}}"
      SUDO_MODE="${SUDO_MODE:-auto}"
      shift 2
      ;;
    --files)
      read -r -a FILES <<< "${2:-}"
      shift 2
      ;;
    --recent-minutes)
      minutes="${2:-}"
      if ! [[ "$minutes" =~ ^[0-9]+$ ]]; then
        echo "Error: --recent-minutes requires an integer." >&2
        exit 1
      fi
      FILES=()
      while IFS= read -r candidate; do
        [[ -z "$candidate" ]] && continue
        FILES+=("$candidate")
      done <<EOF
$(find web/src -type f -mmin "-$minutes" ! -name ".DS_Store" | sort)
EOF
      shift 2
      ;;
    --git-hours)
      hours="${2:-}"
      if ! [[ "$hours" =~ ^[0-9]+$ ]]; then
        echo "Error: --git-hours requires an integer." >&2
        exit 1
      fi
      collect_git_hours_files "$hours"
      shift 2
      ;;
    --no-restart)
      NO_RESTART="1"
      shift
      ;;
    --sudo-mode)
      SUDO_MODE="${2:-}"
      shift 2
      ;;
    --dry-run)
      DRY_RUN="1"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ "$MODE" != "bind" && "$MODE" != "image" ]]; then
  echo "Error: --mode must be 'bind' or 'image'." >&2
  exit 1
fi
if [[ "$SUDO_MODE" != "auto" && "$SUDO_MODE" != "always" && "$SUDO_MODE" != "never" ]]; then
  echo "Error: --sudo-mode must be auto|always|never." >&2
  exit 1
fi

if [[ ${#FILES[@]} -eq 0 ]]; then
  echo "Error: No files selected for upload." >&2
  exit 1
fi

for file in "${FILES[@]}"; do
  if [[ ! -f "$file" ]]; then
    echo "Error: Local file not found: $file" >&2
    exit 1
  fi
done

echo "Deploy target: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}"
echo "Remote base:  ${REMOTE_BASE}"
echo "Mode:         ${MODE}"
echo "Files:"
for file in "${FILES[@]}"; do
  echo "  - $file"
done

for file in "${FILES[@]}"; do
  remote_rel="$(to_remote_rel_path "$file")"
  remote_path="${REMOTE_BASE}/${remote_rel}"
  remote_dir="$(dirname "$remote_path")"
  SSH_CMD="$(build_ssh_cmd)"
  SCP_CMD="$(build_scp_cmd)"
  run_cmd "${SSH_CMD} \"mkdir -p '${remote_dir}'\""
  run_cmd "${SCP_CMD} '${file}' '${REMOTE_USER}@${REMOTE_HOST}:${remote_path}'"
done

if [[ "$NO_RESTART" == "1" ]]; then
  echo "Upload complete (restart/rebuild skipped)."
  exit 0
fi

if [[ "$MODE" == "bind" ]]; then
  SSH_CMD="$(build_ssh_cmd)"
  run_cmd "${SSH_CMD} '
set -e
cd \"${REMOTE_BASE}\"
SUDO_MODE=\"${SUDO_MODE}\"
SUDO_PASSWORD=\"${SUDO_PASSWORD}\"
DOCKER_BIN=\"\"
if command -v docker >/dev/null 2>&1; then
  DOCKER_BIN=\"\$(command -v docker)\"
elif [[ -x /usr/local/bin/docker ]]; then
  DOCKER_BIN=\"/usr/local/bin/docker\"
elif [[ -x /usr/bin/docker ]]; then
  DOCKER_BIN=\"/usr/bin/docker\"
elif [[ -x /var/packages/ContainerManager/target/usr/bin/docker ]]; then
  DOCKER_BIN=\"/var/packages/ContainerManager/target/usr/bin/docker\"
fi

docker_cmd() {
  if [[ \"\$USE_SUDO\" == \"1\" ]]; then
    if [[ -n \"\$SUDO_PASSWORD\" ]]; then
      printf \"%s\\n\" \"\$SUDO_PASSWORD\" | sudo -S -p \"\" \"\$DOCKER_BIN\" \"\$@\"
    else
      sudo \"\$DOCKER_BIN\" \"\$@\"
    fi
  else
    \"\$DOCKER_BIN\" \"\$@\"
  fi
}

USE_SUDO=\"0\"
if [[ \"\$SUDO_MODE\" == \"always\" ]]; then
  USE_SUDO=\"1\"
elif [[ \"\$SUDO_MODE\" == \"auto\" ]]; then
  if ! \"\$DOCKER_BIN\" info >/dev/null 2>&1; then
    USE_SUDO=\"1\"
  fi
fi

if [[ -n \"\$DOCKER_BIN\" ]] && docker_cmd compose version >/dev/null 2>&1; then
  docker_cmd compose restart
elif command -v docker-compose >/dev/null 2>&1; then
  docker-compose restart
elif [[ -n \"\$DOCKER_BIN\" ]]; then
  if [[ -n \"${CONTAINER_NAME:-}\" ]]; then
    docker_cmd restart \"${CONTAINER_NAME}\"
  else
    ids=\$(docker_cmd ps --filter \"name=maneshtrader\" -q)
    if [[ -z \"\$ids\" ]]; then
      echo \"No docker compose command found, and no running containers matched name=maneshtrader.\" >&2
      echo \"Set CONTAINER_NAME=<your-container-name> and rerun.\" >&2
      exit 1
    fi
    docker_cmd restart \$ids
  fi
else
  echo \"No docker or docker compose command found on remote host.\" >&2
  exit 1
fi
'"
  echo "Upload + container restart complete."
else
  SSH_CMD="$(build_ssh_cmd)"
  run_cmd "${SSH_CMD} '
set -e
cd \"${REMOTE_BASE}\"
SUDO_MODE=\"${SUDO_MODE}\"
SUDO_PASSWORD=\"${SUDO_PASSWORD}\"
DOCKER_BIN=\"\"
if command -v docker >/dev/null 2>&1; then
  DOCKER_BIN=\"\$(command -v docker)\"
elif [[ -x /usr/local/bin/docker ]]; then
  DOCKER_BIN=\"/usr/local/bin/docker\"
elif [[ -x /usr/bin/docker ]]; then
  DOCKER_BIN=\"/usr/bin/docker\"
elif [[ -x /var/packages/ContainerManager/target/usr/bin/docker ]]; then
  DOCKER_BIN=\"/var/packages/ContainerManager/target/usr/bin/docker\"
fi

docker_cmd() {
  if [[ \"\$USE_SUDO\" == \"1\" ]]; then
    if [[ -n \"\$SUDO_PASSWORD\" ]]; then
      printf \"%s\\n\" \"\$SUDO_PASSWORD\" | sudo -S -p \"\" \"\$DOCKER_BIN\" \"\$@\"
    else
      sudo \"\$DOCKER_BIN\" \"\$@\"
    fi
  else
    \"\$DOCKER_BIN\" \"\$@\"
  fi
}

USE_SUDO=\"0\"
if [[ \"\$SUDO_MODE\" == \"always\" ]]; then
  USE_SUDO=\"1\"
elif [[ \"\$SUDO_MODE\" == \"auto\" ]]; then
  if ! \"\$DOCKER_BIN\" info >/dev/null 2>&1; then
    USE_SUDO=\"1\"
  fi
fi

if [[ -n \"\$DOCKER_BIN\" ]] && docker_cmd compose version >/dev/null 2>&1; then
  docker_cmd compose up -d --build
elif command -v docker-compose >/dev/null 2>&1; then
  docker-compose up -d --build
else
  echo \"No docker compose command found on remote host.\" >&2
  exit 1
fi
'"
  echo "Upload + image rebuild complete."
fi
