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

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

TEST_COMMAND="${TEST_COMMAND:-composer test:unit}"
SOURCE_TARGET="${SOURCE_TARGET:-}"
SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_HOST:-}}"
SOURCE_PORT="${SOURCE_PORT:-${CONFIG_DB_PORT:-3306}}"
SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DATABASE:-}}"
SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_USER:-}}"
SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_PASSWORD:-}}"
NETWORK_NAME="${NETWORK_NAME:-api-test-net}"
DB_CONTAINER_NAME="${DB_CONTAINER_NAME:-api-test-db}"
REDIS_CONTAINER_NAME="${REDIS_CONTAINER_NAME:-api-test-redis}"
PHP_IMAGE="${PHP_IMAGE:-api-php-test-runner}"
CLONE_DATABASE="${CLONE_DATABASE:-}"
CLONE_ROOT_PASSWORD="${CLONE_ROOT_PASSWORD:-test_root_password}"
SKIP_BUILD="${SKIP_BUILD:-0}"
FORCE_BUILD="${FORCE_BUILD:-0}"
SKIP_TESTS="${SKIP_TESTS:-0}"
KEEP_CONTAINERS="${KEEP_CONTAINERS:-0}"
FORCE="${FORCE:-0}"

if [[ -f ".env" ]]; then
  # shellcheck disable=SC2046
  export $(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' .env | sed 's/\r$//')
  SOURCE_TARGET="${SOURCE_TARGET:-${CONFIG_DB_TARGET:-}}"
fi

SOURCE_TARGET="${SOURCE_TARGET:-live}"
SOURCE_TARGET="$(echo "${SOURCE_TARGET}" | tr '[:upper:]' '[:lower:]')"
if [[ "${SOURCE_TARGET}" != "live" && "${SOURCE_TARGET}" != "debug" ]]; then
  SOURCE_TARGET="live"
fi

if [[ "${SOURCE_TARGET}" == "debug" ]]; then
  SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_DEBUG_HOST:-${CONFIG_DB_HOST:-}}}"
  SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DEBUG_DATABASE:-${CONFIG_DB_DATABASE:-}}}"
  SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_DEBUG_USER:-${CONFIG_DB_USER:-}}}"
  SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_DEBUG_PASSWORD:-${CONFIG_DB_PASSWORD:-}}}"
else
  SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_HOST:-}}"
  SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DATABASE:-}}"
  SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_USER:-}}"
  SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_PASSWORD:-}}"
fi

if [[ -z "${SOURCE_HOST}" || -z "${SOURCE_DATABASE}" || -z "${SOURCE_USER}" || -z "${SOURCE_PASSWORD}" ]]; then
  echo "Missing source DB credentials for target '${SOURCE_TARGET}'. Set CONFIG_DB_TARGET and CONFIG_DB_* / CONFIG_DB_DEBUG_* in .env or env vars."
  exit 1
fi

if [[ -z "${CLONE_DATABASE}" ]]; then
  CLONE_DATABASE="${SOURCE_DATABASE}_test_clone"
fi

if ! command -v docker >/dev/null 2>&1; then
  echo "Docker is required but was not found in PATH."
  exit 1
fi

if [[ "${FORCE}" != "1" ]]; then
  echo "This will clone data from the '${SOURCE_TARGET}' database target into a local Docker MySQL container."
  read -r -p "Type CLONE to continue: " confirmation
  if [[ "${confirmation}" != "CLONE" ]]; then
    echo "Cancelled."
    exit 1
  fi
fi

remove_container_if_exists() {
  local name="$1"
  if docker ps -aq --filter "name=^${name}$" | grep -q .; then
    docker rm -f "${name}" >/dev/null
  fi
}

if [[ "${SKIP_BUILD}" != "1" ]]; then
  if docker image inspect "${PHP_IMAGE}" >/dev/null 2>&1 && [[ "${FORCE_BUILD}" != "1" ]]; then
    echo "Using cached PHP test image (${PHP_IMAGE}). Set FORCE_BUILD=1 to rebuild."
  else
    echo "Building PHP test image (${PHP_IMAGE})..."
    docker build -f services/php/Dockerfile -t "${PHP_IMAGE}" .
  fi
fi

if ! docker network ls --format '{{.Name}}' | grep -qx "${NETWORK_NAME}"; then
  echo "Creating docker network ${NETWORK_NAME}..."
  docker network create "${NETWORK_NAME}" >/dev/null
fi

echo "Resetting test containers..."
remove_container_if_exists "${DB_CONTAINER_NAME}"
remove_container_if_exists "${REDIS_CONTAINER_NAME}"

echo "Starting cloned MySQL container (${DB_CONTAINER_NAME})..."
docker run -d \
  --name "${DB_CONTAINER_NAME}" \
  --network "${NETWORK_NAME}" \
  -e "MYSQL_ROOT_PASSWORD=${CLONE_ROOT_PASSWORD}" \
  -e "MYSQL_DATABASE=${CLONE_DATABASE}" \
  mysql:8.4 >/dev/null

for i in $(seq 1 60); do
  if docker exec -e "MYSQL_PWD=${CLONE_ROOT_PASSWORD}" "${DB_CONTAINER_NAME}" sh -lc "mysqladmin -u root ping --silent" >/dev/null 2>&1; then
    break
  fi
  if [[ "$i" -eq 60 ]]; then
    echo "Timed out waiting for ${DB_CONTAINER_NAME} to be ready."
    exit 1
  fi
  sleep 2
done

echo "Cloning '${SOURCE_TARGET}' database ${SOURCE_DATABASE} from ${SOURCE_HOST} into ${DB_CONTAINER_NAME}/${CLONE_DATABASE}..."
DUMP_DIR="${ROOT_DIR}/.tmp-db-clone"
DUMP_FILE="${DUMP_DIR}/dump.sql"
mkdir -p "${DUMP_DIR}"
rm -f "${DUMP_FILE}"

docker run --rm \
  -e "MYSQL_PWD=${SOURCE_PASSWORD}" \
  -v "${DUMP_DIR}:/dump" \
  mysql:8.4 \
  sh -lc "exec mysqldump --compress --single-transaction --quick --set-gtid-purged=OFF -h '${SOURCE_HOST}' -P '${SOURCE_PORT}' -u '${SOURCE_USER}' '${SOURCE_DATABASE}' > /dump/dump.sql"

if [[ ! -f "${DUMP_FILE}" ]]; then
  echo "Database dump failed."
  exit 1
fi

docker run --rm \
  --network "${NETWORK_NAME}" \
  -e "MYSQL_PWD=${CLONE_ROOT_PASSWORD}" \
  -v "${DUMP_DIR}:/dump" \
  mysql:8.4 \
  sh -lc "exec mysql -h '${DB_CONTAINER_NAME}' -u root '${CLONE_DATABASE}' < /dump/dump.sql"

rm -f "${DUMP_FILE}"

echo "Starting isolated Redis container (${REDIS_CONTAINER_NAME})..."
docker run -d --name "${REDIS_CONTAINER_NAME}" --network "${NETWORK_NAME}" redis:7 >/dev/null

if [[ "${SKIP_TESTS}" != "1" ]]; then
  echo "Running tests in a separate PHP container against cloned DB..."
  docker run --rm \
    --network "${NETWORK_NAME}" \
    --env-file "${ROOT_DIR}/.env" \
    -e "CONFIG_DB_HOST=${DB_CONTAINER_NAME}" \
    -e "CONFIG_DB_DATABASE=${CLONE_DATABASE}" \
    -e "CONFIG_DB_USER=root" \
    -e "CONFIG_DB_PASSWORD=${CLONE_ROOT_PASSWORD}" \
    -e "REDIS_CONFIG_HOST=${REDIS_CONTAINER_NAME}" \
    -e "AUTO_COMPOSER_INSTALL=false" \
    -v "${ROOT_DIR}/services/nginx/app:/var/www/html" \
    -v "${ROOT_DIR}/services/php/php.ini:/usr/local/etc/php/conf.d/zz-custom.ini:ro" \
    "${PHP_IMAGE}" \
    sh -lc "cd /var/www/html && if [ ! -f vendor/autoload.php ]; then composer install --no-interaction --prefer-dist; fi && ${TEST_COMMAND}"
fi

if [[ "${KEEP_CONTAINERS}" != "1" ]]; then
  echo "Cleaning up test containers..."
  remove_container_if_exists "${REDIS_CONTAINER_NAME}"
  remove_container_if_exists "${DB_CONTAINER_NAME}"
else
  echo "Keeping containers for inspection:"
  echo "  DB: ${DB_CONTAINER_NAME}"
  echo "  Redis: ${REDIS_CONTAINER_NAME}"
fi

echo "Done."
