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

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

HOST="${HOST:-pr@192.168.2.19}"
TARGET="${TARGET:-/opt/rental-system}"
MODE="${1:-smart}"
PLAN_ONLY="${PLAN_ONLY:-0}"
SUDO_PASSWORD="${SUDO_PASSWORD:-Alicja}"
REMOTE_SHELL="${REMOTE_SHELL:-ssh -o StrictHostKeyChecking=no}"

INSTALL_DEPS=0
BUILD_SHARED=0
BUILD_API=0
BUILD_WEB=0
RUN_MIGRATIONS=0
RESTART_API=0
RESTART_WEB=0
DAEMON_RELOAD=0

usage() {
  cat <<'EOF'
Usage: ./scripts/deploy-remote.sh [smart|web|api|migrate|full|sync]

Modes:
  smart    Decide automatically based on changed files compared to the deployed tree.
  web      Sync repo, build shared+web, restart only rental-web.service.
  api      Sync repo, build shared+api, restart only rental-api.service.
  migrate  Sync repo, run DB migrations, restart only rental-api.service.
  full     Sync repo, install deps, build shared+api+web, run migrations, restart both services.
  sync     Sync repo only. No build, migrations or restarts.

Environment:
  HOST, TARGET, SUDO_PASSWORD, PLAN_ONLY=1
EOF
}

sync_repo() {
  rsync -az --delete -e "${REMOTE_SHELL}" \
    --exclude ".git" \
    --exclude ".env" \
    --exclude ".env.local" \
    --exclude ".env.bak*" \
    --exclude "node_modules" \
    --exclude ".next" \
    --exclude "dist" \
    "${ROOT_DIR}/" "${HOST}:${TARGET}"
}

collect_changed_files() {
  rsync -az --delete --dry-run --itemize-changes --out-format='%i|%n' -e "${REMOTE_SHELL}" \
    --exclude ".git" \
    --exclude ".env" \
    --exclude ".env.local" \
    --exclude ".env.bak*" \
    --exclude "node_modules" \
    --exclude ".next" \
    --exclude "dist" \
    "${ROOT_DIR}/" "${HOST}:${TARGET}" | awk -F'|' '
      /^\*deleting / {
        sub(/^\*deleting +/, "", $0)
        print $0
        next
      }
      NF >= 2 && $2 != "" {
        attrs = substr($1, 3)
        gsub(/[. ]/, "", attrs)
        if (attrs == "t") {
          next
        }
        print $2
      }
    '
}

mark_shared_change() {
  BUILD_SHARED=1
  BUILD_API=1
  BUILD_WEB=1
  RESTART_API=1
  RESTART_WEB=1
}

mark_api_change() {
  BUILD_API=1
  RESTART_API=1
}

mark_web_change() {
  BUILD_WEB=1
  RESTART_WEB=1
}

mark_migration_change() {
  RUN_MIGRATIONS=1
  RESTART_API=1
}

plan_smart_mode() {
  local changed_files=("$@")

  for path in "${changed_files[@]}"; do
    case "${path}" in
      package-lock.json)
        INSTALL_DEPS=1
        ;;
      tsconfig.base.json)
        mark_shared_change
        ;;
      packages/shared/package.json)
        INSTALL_DEPS=1
        mark_shared_change
        ;;
      packages/shared/*)
        mark_shared_change
        ;;
      apps/web/package.json)
        INSTALL_DEPS=1
        mark_web_change
        ;;
      apps/web/*)
        mark_web_change
        ;;
      apps/api/package.json)
        INSTALL_DEPS=1
        mark_api_change
        ;;
      apps/api/src/db/migrations/*)
        mark_migration_change
        ;;
      apps/api/*)
        mark_api_change
        ;;
      deploy/systemd/rental-api.service)
        DAEMON_RELOAD=1
        RESTART_API=1
        ;;
      deploy/systemd/rental-web.service)
        DAEMON_RELOAD=1
        RESTART_WEB=1
        ;;
      scripts/start-api.sh)
        RESTART_API=1
        ;;
      scripts/start-web.sh)
        RESTART_WEB=1
        ;;
    esac
  done

  if [[ "${INSTALL_DEPS}" == "1" && "${BUILD_SHARED}${BUILD_API}${BUILD_WEB}" == "000" ]]; then
    mark_shared_change
  fi
}

print_plan() {
  echo "Mode: ${MODE}"
  echo "Host: ${HOST}"
  echo "Target: ${TARGET}"
  echo "Plan:"
  echo "  install_deps=${INSTALL_DEPS}"
  echo "  build_shared=${BUILD_SHARED}"
  echo "  build_api=${BUILD_API}"
  echo "  build_web=${BUILD_WEB}"
  echo "  run_migrations=${RUN_MIGRATIONS}"
  echo "  daemon_reload=${DAEMON_RELOAD}"
  echo "  restart_api=${RESTART_API}"
  echo "  restart_web=${RESTART_WEB}"
}

case "${MODE}" in
  smart|web|api|migrate|full|sync)
    ;;
  -h|--help|help)
    usage
    exit 0
    ;;
  *)
    usage >&2
    exit 1
    ;;
esac

CHANGED_FILES=()

if [[ "${MODE}" == "smart" ]]; then
  CHANGED_OUTPUT="$(collect_changed_files)"

  if [[ -n "${CHANGED_OUTPUT}" ]]; then
    while IFS= read -r changed_path; do
      CHANGED_FILES+=("${changed_path}")
    done <<< "${CHANGED_OUTPUT}"
  fi

  if [[ "${#CHANGED_FILES[@]}" -eq 0 ]]; then
    echo "No changes detected between local workspace and ${HOST}:${TARGET}."
    exit 0
  fi

  plan_smart_mode "${CHANGED_FILES[@]}"
else
  case "${MODE}" in
    web)
      BUILD_SHARED=1
      BUILD_WEB=1
      RESTART_WEB=1
      ;;
    api)
      BUILD_SHARED=1
      BUILD_API=1
      RESTART_API=1
      ;;
    migrate)
      RUN_MIGRATIONS=1
      RESTART_API=1
      ;;
    full)
      INSTALL_DEPS=1
      BUILD_SHARED=1
      BUILD_API=1
      BUILD_WEB=1
      RUN_MIGRATIONS=1
      RESTART_API=1
      RESTART_WEB=1
      ;;
    sync)
      ;;
  esac
fi

print_plan

if [[ "${MODE}" == "smart" ]]; then
  echo "Changed files:"
  printf '  %s\n' "${CHANGED_FILES[@]}"
fi

if [[ "${PLAN_ONLY}" == "1" ]]; then
  echo "PLAN_ONLY=1, skipping sync and remote commands."
  exit 0
fi

sync_repo

if [[ "${INSTALL_DEPS}${BUILD_SHARED}${BUILD_API}${BUILD_WEB}${RUN_MIGRATIONS}${DAEMON_RELOAD}${RESTART_API}${RESTART_WEB}" == "00000000" ]]; then
  echo "Sync completed. No remote build, migrations or restarts were required."
  exit 0
fi

REMOTE_TARGET="$(printf '%q' "${TARGET}")"
REMOTE_PASSWORD="$(printf '%q' "${SUDO_PASSWORD}")"

ssh -o StrictHostKeyChecking=no "${HOST}" \
  "cd ${REMOTE_TARGET} && SUDO_PASSWORD=${REMOTE_PASSWORD} INSTALL_DEPS=${INSTALL_DEPS} BUILD_SHARED=${BUILD_SHARED} BUILD_API=${BUILD_API} BUILD_WEB=${BUILD_WEB} RUN_MIGRATIONS=${RUN_MIGRATIONS} DAEMON_RELOAD=${DAEMON_RELOAD} RESTART_API=${RESTART_API} RESTART_WEB=${RESTART_WEB} bash scripts/deploy-targets.sh"
