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

if [[ -z "${TIIX_DEPLOY_ENV_FILE:-}" || ! -f "${TIIX_DEPLOY_ENV_FILE}" ]]; then
  echo "Arquivo de ambiente do deploy não informado."
  exit 1
fi

# shellcheck disable=SC1090
source "${TIIX_DEPLOY_ENV_FILE}"

REPO_FULL_NAME="${TIIX_DEPLOY_REPO:-}"
BRANCH="${TIIX_DEPLOY_BRANCH:-main}"
WORK_DIR="${TIIX_DEPLOY_WORK_DIR:-}"
TARGET_DIR="${TIIX_DEPLOY_TARGET_DIR:-}"
LOG_FILE="${TIIX_DEPLOY_LOG_FILE:-/tmp/deploy-github-repo.log}"
GIT_BIN="${TIIX_GIT_BIN:-git}"
AUTH_REPO_URL="${TIIX_GITHUB_AUTH_REPO_URL:-}"
RUN_ID="${TIIX_DEPLOY_RUN_ID:-}"
MAPPING_ID="${TIIX_DEPLOY_MAPPING_ID:-}"
DELIVERY_ID="${TIIX_GITHUB_DELIVERY_ID:-}"
EVENT_ID="${TIIX_GITHUB_EVENT_ID:-}"
SENDER_LOGIN="${TIIX_GITHUB_SENDER_LOGIN:-}"
PUSHER_NAME="${TIIX_DEPLOY_PUSHER:-}"
HEAD_SHA="${TIIX_DEPLOY_HEAD_SHA:-}"
CALLBACK_URL="${TIIX_DEPLOY_CALLBACK_URL:-}"
CALLBACK_SECRET="${TIIX_DEPLOY_CALLBACK_SECRET:-}"
RUN_MIGRATIONS="${TIIX_DEPLOY_RUN_MIGRATIONS:-0}"
PHP_BIN="${TIIX_DEPLOY_PHP_BIN:-php}"
MIGRATIONS_CMD="${TIIX_DEPLOY_MIGRATIONS_CMD:-}"
MIGRATIONS_ARGS="${TIIX_DEPLOY_MIGRATIONS_ARGS:-run --no-interaction}"

LOCK_KEY="$(echo "${REPO_FULL_NAME:-generic}" | tr '/:' '_-')"
LOCK_FILE="/tmp/${LOCK_KEY}.lock"
CALLBACK_ALREADY_SENT=0

mkdir -p "$(dirname "${LOG_FILE}")"

COMMIT_BEFORE=""
COMMIT_AFTER=""

json_escape() {
  local s="${1:-}"
  s="${s//\\/\\\\}"
  s="${s//\"/\\\"}"
  s="${s//$'\n'/\\n}"
  s="${s//$'\r'/\\r}"
  s="${s//$'\t'/\\t}"
  printf '%s' "$s"
}

callback_finish() {
  local status="$1"
  local exit_code="$2"
  local summary="$3"

  CALLBACK_ALREADY_SENT=1

  if [[ -z "${CALLBACK_URL}" ]]; then
    echo ">> callback finish ignorado: CALLBACK_URL vazio"
    return 0
  fi

  local finish_url="${CALLBACK_URL%/webhook}/finish"

  local payload
  payload=$(cat <<JSON
{"run_id":"$(json_escape "${RUN_ID}")","mapping_id":"$(json_escape "${MAPPING_ID}")","status":"$(json_escape "${status}")","exit_code":${exit_code},"commit_before":"$(json_escape "${COMMIT_BEFORE}")","commit_after":"$(json_escape "${COMMIT_AFTER}")","summary":"$(json_escape "${summary}")","github_delivery_id":"$(json_escape "${DELIVERY_ID}")","github_event_id":"$(json_escape "${EVENT_ID}")","stdout_text":"","stderr_text":"","github_sender_login":"$(json_escape "${SENDER_LOGIN}")","pusher_name":"$(json_escape "${PUSHER_NAME}")"}
JSON
)

  echo ">> callback finish url: ${finish_url}"
  echo ">> callback finish run_id: ${RUN_ID}"
  echo ">> callback finish mapping_id: ${MAPPING_ID}"
  echo ">> callback finish delivery_id: ${DELIVERY_ID}"
  echo ">> callback finish event_id: ${EVENT_ID}"
  echo ">> callback finish status: ${status}"

  local response=""
  local curl_exit=0

  response=$(curl -i -sS -X POST "${finish_url}" \
    -H "Content-Type: application/json" \
    -H "X-TIIX-Deploy-Key: ${CALLBACK_SECRET}" \
    -d "${payload}" 2>&1) || curl_exit=$?

  echo ">> callback finish curl_exit: ${curl_exit}"
  echo ">> callback finish response:"
  echo "${response}"

  return 0
}

{
  echo "=================================================="
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Iniciando deploy de ${REPO_FULL_NAME}"
  echo ">> sender_login: ${SENDER_LOGIN}"
  echo ">> pusher_name: ${PUSHER_NAME}"
  echo ">> delivery_id: ${DELIVERY_ID}"
  echo ">> event_id: ${EVENT_ID}"
  echo ">> head_sha: ${HEAD_SHA}"
  echo ">> run_id: ${RUN_ID}"
  echo ">> mapping_id: ${MAPPING_ID}"

  flock -n 9 || {
    echo "Deploy já em execução para ${REPO_FULL_NAME}."
    callback_finish "error" 1 "Deploy já em execução para ${REPO_FULL_NAME}"
    exit 1
  }

  if [[ -z "${REPO_FULL_NAME}" || -z "${WORK_DIR}" || -z "${TARGET_DIR}" || -z "${AUTH_REPO_URL}" ]]; then
    echo "Variáveis obrigatórias ausentes."
    callback_finish "error" 1 "Variáveis obrigatórias ausentes"
    exit 1
  fi

  mkdir -p "${WORK_DIR}"
  mkdir -p "${TARGET_DIR}"

  if [[ ! -d "${WORK_DIR}/.git" ]]; then
    echo ">> clone inicial"
    rm -rf "${WORK_DIR}"
    "${GIT_BIN}" clone "${AUTH_REPO_URL}" "${WORK_DIR}"
  fi

  cd "${WORK_DIR}"

  echo ">> git remote set-url origin"
  "${GIT_BIN}" remote set-url origin "${AUTH_REPO_URL}"

  COMMIT_BEFORE="$("${GIT_BIN}" rev-parse HEAD 2>/dev/null || true)"
  echo ">> git fetch origin ${BRANCH}"
  "${GIT_BIN}" fetch origin "${BRANCH}" --prune

  if [[ -n "${HEAD_SHA}" ]]; then
    echo ">> git reset --hard ${HEAD_SHA}"
    "${GIT_BIN}" reset --hard "${HEAD_SHA}"
  else
    echo ">> git reset --hard origin/${BRANCH}"
    "${GIT_BIN}" reset --hard "origin/${BRANCH}"
  fi

  echo ">> git clean -fd"
  "${GIT_BIN}" clean -fd

  COMMIT_AFTER="$("${GIT_BIN}" rev-parse HEAD 2>/dev/null || true)"
  echo ">> commit before: ${COMMIT_BEFORE}"
  echo ">> commit after:  ${COMMIT_AFTER}"

  echo ">> rsync para produção"
  /bin/rsync -av --delete \
    --exclude=".git" \
    --exclude=".github" \
    "${WORK_DIR}/" "${TARGET_DIR}/"

  echo ">> permissões"
  find "${TARGET_DIR}" -type d -exec chmod 755 {} \;
  find "${TARGET_DIR}" -type f -exec chmod 644 {} \;

  if [[ "${RUN_MIGRATIONS}" == "1" || "${RUN_MIGRATIONS}" == "true" || "${RUN_MIGRATIONS}" == "yes" ]]; then
    if [[ -z "${MIGRATIONS_CMD}" ]]; then
      MIGRATIONS_CMD="${TARGET_DIR}/tools/migrate-sql.php"
    fi

    echo ">> migrations SQL"
    echo ">> migrations cmd: ${PHP_BIN} ${MIGRATIONS_CMD} ${MIGRATIONS_ARGS}"

    if [[ ! -f "${MIGRATIONS_CMD}" ]]; then
      echo "Script de migrations nÃ£o encontrado: ${MIGRATIONS_CMD}"
      callback_finish "error" 1 "Script de migrations SQL nÃ£o encontrado"
      exit 1
    fi

    # shellcheck disable=SC2086
    if ! "${PHP_BIN}" "${MIGRATIONS_CMD}" ${MIGRATIONS_ARGS}; then
      echo "Falha ao executar migrations SQL."
      callback_finish "error" 1 "Falha ao executar migrations SQL para ${REPO_FULL_NAME}"
      exit 1
    fi
  else
    echo ">> migrations SQL desabilitadas"
  fi

  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deploy concluído com sucesso"
  callback_finish "success" 0 "Deploy concluído com sucesso para ${REPO_FULL_NAME}"
} 9>"${LOCK_FILE}" >> "${LOG_FILE}" 2>&1 || {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Falha no deploy de ${REPO_FULL_NAME}" >> "${LOG_FILE}"
  if [[ "${CALLBACK_ALREADY_SENT:-0}" != "1" ]]; then
    callback_finish "error" 1 "Falha no deploy de ${REPO_FULL_NAME}"
  fi
  exit 1
}
