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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ARCHIVE_BASE_DEFAULT="/tmp/mosquito-archives"
ARCHIVE_TAG_DEFAULT="$(date +%Y%m%d_%H%M%S)"

MODE="archive"              # archive | delete
APPLY="false"               # false => dry-run
INCLUDE_TRACKED="false"     # true => include git tracked paths
FAIL_ON_FOUND="false"       # true => exit non-zero when cleanup candidates exist
INCLUDE_BUILD_OUTPUTS="false" # true => include dist/target build outputs
ARCHIVE_BASE="${ARCHIVE_BASE_DEFAULT}"
ARCHIVE_TAG="${ARCHIVE_TAG_DEFAULT}"

ARTIFACT_PATHS=(
  "frontend/admin/test-results"
  "frontend/e2e/e2e-results"
  "frontend/e2e/e2e-report"
  "frontend/e2e/playwright-report"
  "frontend/e2e/test-results"
  "frontend/e2e-admin/test-results"
  "frontend/e2e-results"
)

BUILD_OUTPUT_PATHS=(
  "target"
  "frontend/dist"
  "frontend/admin/dist"
  "frontend/h5/dist"
)

ROOT_SPILLOVER_GLOBS=(
  "e2e-test-report-*.md"
  "E2E_TEST*.md"
  "TEST_E2E_*.md"
  "COVERAGE_*.md"
)

usage() {
  cat <<'EOF'
Usage:
  ./scripts/ci/clean-artifacts.sh [--apply] [--mode archive|delete] [--archive-base DIR] [--archive-tag TAG] [--include-tracked] [--include-build-outputs] [--fail-on-found]

Options:
  --apply              Execute cleanup. Without this flag, script runs in dry-run mode.
  --mode MODE          archive (default) | delete
  --archive-base DIR   Archive base dir for archive mode. Default: /tmp/mosquito-archives
  --archive-tag TAG    Archive subdir tag. Default: current timestamp
  --include-tracked    Include git tracked paths (default: skip tracked)
  --include-build-outputs
                      Include build output paths (target, frontend/*/dist)
  --fail-on-found      Exit non-zero when cleanup candidates are found (useful for CI dry-run)
  -h, --help           Show help

Examples:
  ./scripts/ci/clean-artifacts.sh
  ./scripts/ci/clean-artifacts.sh --apply
  ./scripts/ci/clean-artifacts.sh --apply --mode archive --archive-tag manual_cleanup
  ./scripts/ci/clean-artifacts.sh --include-build-outputs --apply --mode archive --archive-tag weekly_cleanup
  ./scripts/ci/clean-artifacts.sh --fail-on-found
EOF
}

log() { echo "[clean-artifacts] $*"; }

is_git_tracked() {
  local rel="$1"
  local out
  out="$(git -C "${ROOT_DIR}" ls-files -- "${rel}" 2>/dev/null || true)"
  [[ -n "${out}" ]]
}

run_cmd() {
  if [[ "${APPLY}" == "true" ]]; then
    "$@"
  else
    log "DRY-RUN: $*"
  fi
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --apply)
      APPLY="true"
      shift
      ;;
    --mode)
      MODE="${2:-}"
      shift 2
      ;;
    --archive-base)
      ARCHIVE_BASE="${2:-}"
      shift 2
      ;;
    --archive-tag)
      ARCHIVE_TAG="${2:-}"
      shift 2
      ;;
    --include-tracked)
      INCLUDE_TRACKED="true"
      shift
      ;;
    --include-build-outputs)
      INCLUDE_BUILD_OUTPUTS="true"
      shift
      ;;
    --fail-on-found)
      FAIL_ON_FOUND="true"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ "${MODE}" != "archive" && "${MODE}" != "delete" ]]; then
  echo "Invalid --mode: ${MODE}" >&2
  exit 1
fi

ARCHIVE_DIR="${ARCHIVE_BASE}/${ARCHIVE_TAG}"

log "root=${ROOT_DIR}"
log "mode=${MODE} apply=${APPLY} include_tracked=${INCLUDE_TRACKED} include_build_outputs=${INCLUDE_BUILD_OUTPUTS} fail_on_found=${FAIL_ON_FOUND}"
if [[ "${INCLUDE_BUILD_OUTPUTS}" == "true" ]] && pgrep -af "spring-boot:run|e2e_continuous_runner.sh|vite" >/dev/null 2>&1; then
  log "WARN: detected active dev/e2e processes; build outputs may be recreated immediately."
fi
if [[ "${MODE}" == "archive" ]]; then
  log "archive_dir=${ARCHIVE_DIR}"
  if [[ "${APPLY}" == "true" ]]; then
    mkdir -p "${ARCHIVE_DIR}"
  fi
fi

cleaned_count=0
skipped_count=0
found_count=0

CANDIDATE_PATHS=("${ARTIFACT_PATHS[@]}")
if [[ "${INCLUDE_BUILD_OUTPUTS}" == "true" ]]; then
  CANDIDATE_PATHS+=("${BUILD_OUTPUT_PATHS[@]}")
fi

for rel in "${CANDIDATE_PATHS[@]}"; do
  abs="${ROOT_DIR}/${rel}"
  if [[ ! -e "${abs}" ]]; then
    continue
  fi

  if [[ "${INCLUDE_TRACKED}" != "true" ]] && is_git_tracked "${rel}"; then
    log "SKIP tracked path: ${rel}"
    skipped_count=$((skipped_count + 1))
    continue
  fi

  if [[ "${MODE}" == "archive" ]]; then
    dest="${ARCHIVE_DIR}/${rel}"
    run_cmd mkdir -p "$(dirname "${dest}")"
    run_cmd mv "${abs}" "${dest}"
    log "ARCHIVE ${rel} -> ${dest}"
  else
    run_cmd rm -rf "${abs}"
    log "DELETE ${rel}"
  fi

  found_count=$((found_count + 1))
  cleaned_count=$((cleaned_count + 1))
done

# Root report spillover (files in repository root)
shopt -s nullglob
for pattern in "${ROOT_SPILLOVER_GLOBS[@]}"; do
  for file in "${ROOT_DIR}"/${pattern}; do
    [[ -f "${file}" ]] || continue
    rel="$(basename "${file}")"

    if [[ "${INCLUDE_TRACKED}" != "true" ]] && is_git_tracked "${rel}"; then
      log "SKIP tracked root file: ${rel}"
      skipped_count=$((skipped_count + 1))
      continue
    fi

    if [[ "${MODE}" == "archive" ]]; then
      dest="${ARCHIVE_DIR}/root-spillover/${rel}"
      run_cmd mkdir -p "$(dirname "${dest}")"
      run_cmd mv "${file}" "${dest}"
      log "ARCHIVE ${rel} -> ${dest}"
    else
      run_cmd rm -f "${file}"
      log "DELETE ${rel}"
    fi

    found_count=$((found_count + 1))
    cleaned_count=$((cleaned_count + 1))
  done
done
shopt -u nullglob

# Move root attach_pid files into tmp/pids
pids_dir="${ROOT_DIR}/tmp/pids"
if compgen -G "${ROOT_DIR}/.attach_pid*" > /dev/null; then
  run_cmd mkdir -p "${pids_dir}"
  while IFS= read -r pid_file; do
    rel_pid="$(basename "${pid_file}")"
    if [[ "${MODE}" == "archive" ]]; then
      if [[ "${APPLY}" == "true" ]]; then
        mv "${pid_file}" "${pids_dir}/${rel_pid}"
      else
        log "DRY-RUN: mv ${pid_file} ${pids_dir}/${rel_pid}"
      fi
      log "MOVE ${rel_pid} -> tmp/pids/"
    else
      run_cmd rm -f "${pid_file}"
      log "DELETE ${rel_pid}"
    fi
    found_count=$((found_count + 1))
    cleaned_count=$((cleaned_count + 1))
  done < <(find "${ROOT_DIR}" -maxdepth 1 -type f -name ".attach_pid*" | sort)
fi

log "done: found=${found_count}, cleaned=${cleaned_count}, skipped=${skipped_count}"
if [[ "${APPLY}" != "true" ]]; then
  log "dry-run completed. Use --apply to execute."
fi

if [[ "${FAIL_ON_FOUND}" == "true" && "${found_count}" -gt 0 ]]; then
  log "fail-on-found enabled: detected ${found_count} cleanup candidates."
  exit 2
fi
