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

if [[ $# -ne 3 ]]; then
  echo "usage: deploy-release.sh TARGET_DIR ARTIFACT RELEASE_ID" >&2
  exit 64
fi

target_dir=$(readlink -m "$1")
artifact=$(readlink -m "$2")
release_id=$3
releases_root=$(readlink -m "${target_dir}/releases")
current_path="${target_dir}/current"
shared_root="${target_dir}/shared"
release_path="${releases_root}/${release_id}"
staging_path="${releases_root}/.${release_id}.staging.$$"

if [[ ! "$release_id" =~ ^[0-9a-f]{7,40}$ ]]; then
  echo "invalid release id" >&2
  exit 65
fi

validate_release_path() {
  local candidate
  candidate=$(readlink -m "$1")
  [[ "$candidate" == "${releases_root}/"* && "$candidate" != "$releases_root" ]]
}

validate_current() {
  if [[ -e "$current_path" && ! -L "$current_path" ]]; then
    echo "current must be absent or a symlink" >&2
    return 1
  fi
  if [[ -L "$current_path" ]]; then
    local raw resolved
    raw=$(readlink "$current_path")
    if [[ "$raw" = /* ]]; then resolved=$(readlink -m "$raw"); else resolved=$(readlink -m "${target_dir}/${raw}"); fi
    validate_release_path "$resolved" || { echo "current escapes releases" >&2; return 1; }
    [[ -d "$resolved" ]] || { echo "current points to a missing release" >&2; return 1; }
  fi
}

validate_current
[[ -f "$artifact" ]] || { echo "artifact not found" >&2; exit 66; }
mkdir -p "$releases_root" "${target_dir}/incoming"
[[ -f "${shared_root}/.env.local" ]] || { echo "shared .env.local missing" >&2; exit 67; }
[[ -f "${shared_root}/public.htaccess" && ! -L "${shared_root}/public.htaccess" ]] || { echo "shared public.htaccess missing or invalid" >&2; exit 67; }
for directory in sessions voices logs; do
  [[ -d "${shared_root}/${directory}" && ! -L "${shared_root}/${directory}" ]] || { echo "invalid shared ${directory}" >&2; exit 67; }
done

if [[ -e "$release_path" || -L "$release_path" ]]; then
  [[ -d "$release_path" && -f "${release_path}/.release-ready" ]] || { echo "existing release is not ready" >&2; exit 68; }
else
  trap 'rm -rf -- "$staging_path"' EXIT
  mkdir -p "$staging_path"
  tar -xzf "$artifact" -C "$staging_path"
  [[ -f "${staging_path}/backend/bin/console" ]] || { echo "backend console missing" >&2; exit 69; }
  [[ -f "${staging_path}/backend/public/index.php" ]] || { echo "front controller missing" >&2; exit 69; }
  [[ -f "${staging_path}/backend/public/app/index.html" ]] || { echo "frontend build missing" >&2; exit 69; }
  [[ -f "${staging_path}/backend/vendor/autoload.php" ]] || { echo "vendor missing" >&2; exit 69; }

  cp "${shared_root}/public.htaccess" "${staging_path}/backend/public/.htaccess"
  ln -s "$shared_root/.env.local" "${staging_path}/backend/.env.local"
  mkdir -p "${staging_path}/backend/var"
  ln -s "$shared_root/sessions" "${staging_path}/backend/var/sessions"
  ln -s "$shared_root/voices" "${staging_path}/backend/var/voices"
  ln -s "$shared_root/logs" "${staging_path}/backend/var/log"

  php "${staging_path}/backend/bin/console" doctrine:migrations:migrate --env=prod --no-interaction
  php "${staging_path}/backend/bin/console" cache:clear --env=prod --no-debug
  php "${staging_path}/backend/bin/console" cache:warmup --env=prod --no-debug
  touch "${staging_path}/.release-ready"
  mv "$staging_path" "$release_path"
  trap - EXIT
fi

validate_release_path "$release_path" || { echo "release escapes releases" >&2; exit 70; }
[[ -f "${release_path}/.release-ready" ]] || { echo "release not ready" >&2; exit 70; }
temporary_link="${target_dir}/.current.${release_id}.$$"
ln -s "releases/${release_id}" "$temporary_link"
mv -Tf "$temporary_link" "$current_path"
echo "activated ${release_id}"
