#!/bin/bash
set -euo pipefail

# Usage: ./rollback-release.sh <release_tag> <target_dir>
# This script is intended to be executed ON THE REMOTE SERVER (OVH) via SSH
# It atomically switches the active release to an existing, immutable release.

if [ "$#" -ne 2 ]; then
    echo "Usage: $0 <release_tag> <target_dir>"
    exit 1
fi

RELEASE_TAG=$1
TARGET_DIR="${2%/}"

# 1. Strictly validate release tag format
if ! [[ "${RELEASE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo "Error: Release tag must match SemVer format (e.g., v1.0.0)."
    exit 1
fi

RELEASES_ROOT=$(readlink -m "${TARGET_DIR}/releases")
RELEASE_PATH="${RELEASES_ROOT}/${RELEASE_TAG}"
CURRENT_TARGET="releases/${RELEASE_TAG}"

# Never allow mv -Tf to replace a real file or directory named `current`.
# The link target must also remain a relative releases/vX.Y.Z path: Apache on
# OVH rejects the absolute-current topology even when the filesystem resolves it.
if [ -L "${TARGET_DIR}/current" ]; then
    CURRENT_LINK_TARGET=$(readlink "${TARGET_DIR}/current")
    if ! [[ "${CURRENT_LINK_TARGET}" =~ ^releases/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        echo "Error: ${TARGET_DIR}/current must be a relative symlink in the form releases/vX.Y.Z (found: ${CURRENT_LINK_TARGET}). Aborting before activation."
        exit 1
    fi

    CURRENT_RELEASE_PATH=$(readlink -m "${TARGET_DIR}/${CURRENT_LINK_TARGET}")
    if [ "${CURRENT_RELEASE_PATH}" != "${RELEASES_ROOT}/${CURRENT_LINK_TARGET#releases/}" ]; then
        echo "Error: ${TARGET_DIR}/current points outside ${RELEASES_ROOT} (${CURRENT_LINK_TARGET}). Aborting before activation."
        exit 1
    fi
elif [ -e "${TARGET_DIR}/current" ]; then
    echo "Error: ${TARGET_DIR}/current exists as a real file or directory (must be a symlink or absent). Aborting before activation."
    exit 1
fi

# 2. Verify that target release exists
if [ ! -d "${RELEASE_PATH}" ]; then
    echo "Error: Release ${RELEASE_PATH} does not exist. Cannot rollback to non-existent release."
    exit 1
fi

# 3. Verify structural integrity of target release
echo "Checking integrity of release ${RELEASE_TAG}..."
if [ ! -f "${RELEASE_PATH}/vendor/autoload.php" ]; then
    echo "Error: ${RELEASE_PATH}/vendor/autoload.php is missing. Release is corrupted."
    exit 1
fi
if [ ! -f "${RELEASE_PATH}/public/index.php" ]; then
    echo "Error: ${RELEASE_PATH}/public/index.php is missing. Release is corrupted."
    exit 1
fi
if [ ! -d "${RELEASE_PATH}/public/build" ]; then
    echo "Error: ${RELEASE_PATH}/public/build is missing. Release is corrupted."
    exit 1
fi
if [ ! -f "${RELEASE_PATH}/.release-ready" ]; then
    echo "Error: ${RELEASE_PATH}/.release-ready is missing. Release is incomplete or unverified."
    exit 1
fi

# Shared targets must exist; valid symlink text alone is insufficient.
if [ ! -f "${TARGET_DIR}/shared/.env" ]; then
    echo "Error: ${TARGET_DIR}/shared/.env is missing."
    exit 1
fi
if [ ! -d "${TARGET_DIR}/shared/storage" ]; then
    echo "Error: ${TARGET_DIR}/shared/storage is missing."
    exit 1
fi
if [ ! -d "${TARGET_DIR}/shared/storage/app/public" ]; then
    echo "Error: ${TARGET_DIR}/shared/storage/app/public is missing."
    exit 1
fi

# 4. Verify that shared symlinks exist (-L) and point strictly to expected canonical destinations
ENV_LINK=$(readlink "${RELEASE_PATH}/.env" 2>/dev/null || true)
if [ ! -L "${RELEASE_PATH}/.env" ] || [ "${ENV_LINK}" != "${TARGET_DIR}/shared/.env" ]; then
    echo "Error: ${RELEASE_PATH}/.env is not a valid symlink pointing to ${TARGET_DIR}/shared/.env (found: '${ENV_LINK}')."
    exit 1
fi

STORAGE_LINK=$(readlink "${RELEASE_PATH}/storage" 2>/dev/null || true)
if [ ! -L "${RELEASE_PATH}/storage" ] || [ "${STORAGE_LINK}" != "${TARGET_DIR}/shared/storage" ]; then
    echo "Error: ${RELEASE_PATH}/storage is not a valid symlink pointing to ${TARGET_DIR}/shared/storage (found: '${STORAGE_LINK}')."
    exit 1
fi

PUB_STORAGE_LINK=$(readlink "${RELEASE_PATH}/public/storage" 2>/dev/null || true)
if [ ! -L "${RELEASE_PATH}/public/storage" ] || [ "${PUB_STORAGE_LINK}" != "${TARGET_DIR}/shared/storage/app/public" ]; then
    echo "Error: ${RELEASE_PATH}/public/storage is not a valid symlink pointing to ${TARGET_DIR}/shared/storage/app/public (found: '${PUB_STORAGE_LINK}')."
    exit 1
fi

echo "Integrity check passed."

# Trap cleanup to guarantee no leftover temporary link on failure
cleanup() {
    local exit_code=$?
    if [ -L "${TARGET_DIR:-}/current.new" ] || [ -f "${TARGET_DIR:-}/current.new" ]; then
        rm -f "${TARGET_DIR}/current.new"
    fi
    exit "${exit_code}"
}
trap cleanup EXIT INT TERM

# 5. Atomic switch to previous release
echo "Switching current symlink to ${RELEASE_PATH}..."
ln -sfn "${CURRENT_TARGET}" "${TARGET_DIR}/current.new"

if ! mv -Tf "${TARGET_DIR}/current.new" "${TARGET_DIR}/current"; then
    echo "Error: mv -Tf failed during rollback."
    exit 1
fi

CURRENT_LINK_TARGET=$(readlink "${TARGET_DIR}/current")
if [ "${CURRENT_LINK_TARGET}" != "${CURRENT_TARGET}" ]; then
    echo "Error: ${TARGET_DIR}/current must point exactly to ${CURRENT_TARGET} after rollback (found: ${CURRENT_LINK_TARGET})."
    exit 1
fi
echo "Switched to ${RELEASE_PATH} atomically using mv -Tf."

echo "Rollback successful. Active release is now: ${RELEASE_TAG} (${RELEASE_PATH})."
