#!/usr/bin/env sh
set -eu

suite="${1:-}"
case "$suite" in
  unit|integration|api|legacy|all)
    ;;
  *)
    echo "Usage: $0 <unit|integration|api|legacy|all>" >&2
    exit 2
    ;;
esac

script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
cd "$repo_root"

compose_files="-f docker-compose.yml -f .github/docker-compose.ci.yml"
project_suffix="$(date +%s)-$$"
export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-php-local-${suite}-${project_suffix}}"
export COMPOSE_PROFILES="${COMPOSE_PROFILES:-dev}"

log_dir=".tmp/ci-logs/$suite"
mkdir -p "$log_dir"

env_backup_dir=".tmp/php-ci-env-backup-$project_suffix"
mkdir -p "$env_backup_dir"
had_env=0
had_env_staging=0
if [ -f .env ]; then
  cp .env "$env_backup_dir/env"
  had_env=1
fi
if [ -f .env.staging ]; then
  cp .env.staging "$env_backup_dir/env.staging"
  had_env_staging=1
fi

cp .github/ci.env .env
cp .github/ci.env.staging .env.staging

collect_logs() {
  status="$1"
  if [ "$status" -eq 0 ]; then
    return
  fi

  mkdir -p "$log_dir"
  docker compose $compose_files ps > "$log_dir/docker-compose-ps.txt" 2>&1 || true
  docker compose $compose_files logs --no-color > "$log_dir/docker-compose.log" 2>&1 || true
  docker compose $compose_files cp php1:/var/www/html/build/logs "$log_dir/app-build-logs" >/dev/null 2>&1 || true
  docker compose $compose_files cp php1:/var/log/php "$log_dir/php-logs" >/dev/null 2>&1 || true
}

retry_command() {
  max_attempts="$1"
  shift
  attempt=1
  while :; do
    "$@" && return 0
    status="$?"
    if [ "$attempt" -ge "$max_attempts" ]; then
      return "$status"
    fi
    sleep_seconds=$((attempt * 5))
    echo "Command failed with status $status; retrying in ${sleep_seconds}s (attempt $((attempt + 1))/$max_attempts): $*" >&2
    sleep "$sleep_seconds"
    attempt=$((attempt + 1))
  done
}

composer_install() {
  dist_attempts="${PHP_CI_COMPOSER_RETRIES:-3}"
  source_attempts="${PHP_CI_COMPOSER_SOURCE_RETRIES:-2}"

  if retry_command "$dist_attempts" \
    docker compose $compose_files exec -T php1 sh -lc \
    'cd /var/www/html && composer install --no-interaction --prefer-dist --no-progress'; then
    return 0
  fi

  echo "Composer dist install failed after ${dist_attempts} attempts; retrying with --prefer-source." >&2
  retry_command "$source_attempts" \
    docker compose $compose_files exec -T php1 sh -lc \
    'cd /var/www/html && composer install --no-interaction --prefer-source --no-progress'
}

configure_ci_docker_subnet() {
  if [ -n "${CI_DOCKER_SUBNET:-}" ]; then
    return
  fi

  checksum="$(printf '%s' "$COMPOSE_PROJECT_NAME" | cksum | awk '{print $1}')"
  subnet_second=$((64 + ((checksum / 256) % 64)))
  subnet_third=$((checksum % 256))
  export CI_DOCKER_SUBNET="10.${subnet_second}.${subnet_third}.0/24"
}

cleanup() {
  status="$?"
  collect_logs "$status"
  docker compose $compose_files down -v >/dev/null 2>&1 || true
  if [ "$had_env" -eq 1 ]; then
    cp "$env_backup_dir/env" .env
  else
    rm -f .env
  fi
  if [ "$had_env_staging" -eq 1 ]; then
    cp "$env_backup_dir/env.staging" .env.staging
  else
    rm -f .env.staging
  fi
  rm -rf "$env_backup_dir"
  exit "$status"
}
trap cleanup EXIT INT TERM

configure_ci_docker_subnet
sh scripts/ci-docker-compose-up.sh redis mysql-debug php1

docker compose $compose_files exec -T php1 sh -lc '
  set -eu
  for i in $(seq 1 90); do
    if MYSQL_PWD="${CONFIG_DB_PASSWORD:-debug_root_password}" mysqladmin \
      -h "${CONFIG_DB_HOST:-mysql-debug}" \
      -P "${CONFIG_DB_PORT:-3306}" \
      -u "${CONFIG_DB_USER:-root}" \
      ping --silent >/dev/null 2>&1; then
      exit 0
    fi
    sleep 1
  done
  echo "Timed out waiting for mysql-debug" >&2
  exit 1
'

tar \
  --exclude='./vendor' \
  --exclude='./.phpunit.cache' \
  --exclude='./build/logs' \
  -C services/nginx/app -cf - . \
  | docker compose $compose_files exec -T php1 tar --no-same-owner -C /var/www/html -xf -

docker compose $compose_files exec -T php1 sh -lc 'rm -rf /var/www/repo-root && mkdir -p /var/www/repo-root'
tar \
  -cf - \
  Dockerfile \
  Dockerfile.coolify-api \
  services/php/Dockerfile \
  services/php/php-fpm-pool.conf \
  | docker compose $compose_files exec -T php1 tar --no-same-owner -C /var/www/repo-root -xf -

composer_install

docker compose $compose_files exec -T php1 sh -lc \
  "cd /var/www/html && PLENO_REPO_ROOT_FOR_TESTS=/var/www/repo-root composer test:ci:$suite"
