#!/usr/bin/env bash
#
# deploy.sh — one-shot release pipeline for Blocksify.
#
#   1. Pre-flight (git clean, version sync, config present)
#   2. composer install --no-dev --optimize-autoloader
#   3. npm run build
#   4. Checkout / refresh ../blocksify-svn working copy
#   5. rsync source -> trunk (using .svnignore as exclude list)
#   6. rsync wp.org assets (banner/icon/screenshot only) -> /assets/
#   7. rsync source -> tags/${VERSION} (created if missing, updated if exists)
#   8. svn add/rm reconciliation
#   9. svn commit
#
# Version policy: ${VERSION} is read from package.json. The script never
# modifies it — bump the version manually before deploying a new release.
# Tag policy: the tag matching ${VERSION} is always synced. If it doesn't
# exist on SVN yet, this run creates it; otherwise its content is updated to
# match trunk.
#
# Flags:
#   --allow-dirty     Skip the "git working tree must be clean" check.
#   --skip-build      Reuse existing build/ output (skip npm build).
#   --skip-composer   Reuse existing vendor/ (skip composer install).
#   --dry-run         Stop right before `svn commit`, leave working copy for inspection.
#
# Requires svn-config.cfg in the plugin root with:
#   SVN_REPO=blocksify
#   SVN_USERNAME=...
#   SVN_PASSWORD=...

set -euo pipefail

# ---------- flag parsing ----------
ALLOW_DIRTY=0
SKIP_BUILD=0
SKIP_COMPOSER=0
DRY_RUN=0
for arg in "$@"; do
    case "$arg" in
        --allow-dirty)   ALLOW_DIRTY=1 ;;
        --skip-build)    SKIP_BUILD=1 ;;
        --skip-composer) SKIP_COMPOSER=1 ;;
        --dry-run)       DRY_RUN=1 ;;
        -h|--help)
            sed -n '2,/^set -e/p' "$0" | sed 's/^# \{0,1\}//; /^set -e/d'
            exit 0
            ;;
        *)
            printf 'Unknown flag: %s\n' "$arg" >&2
            exit 2
            ;;
    esac
done

# ---------- paths ----------
PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SVN_DIR="$(cd "${PLUGIN_DIR}/.." && pwd)/blocksify-svn"
cd "${PLUGIN_DIR}"

# ---------- output helpers ----------
if [[ -t 1 ]]; then
    C_BLUE=$'\033[1;34m'; C_GREEN=$'\033[1;32m'; C_YELLOW=$'\033[1;33m'
    C_RED=$'\033[1;31m'; C_RESET=$'\033[0m'
else
    C_BLUE=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_RESET=''
fi
step() { printf '%s==> %s%s\n' "$C_BLUE" "$1" "$C_RESET"; }
ok()   { printf '%s✓ %s%s\n'  "$C_GREEN" "$1" "$C_RESET"; }
warn() { printf '%s! %s%s\n'  "$C_YELLOW" "$1" "$C_RESET"; }
err()  { printf '%s✗ %s%s\n'  "$C_RED" "$1" "$C_RESET" >&2; }

# ---------- load config ----------
CONFIG_FILE="${PLUGIN_DIR}/svn-config.cfg"
if [[ ! -f "${CONFIG_FILE}" ]]; then
    err "${CONFIG_FILE} not found."
    echo "    Copy svn-config-sample.cfg to svn-config.cfg and fill in credentials." >&2
    exit 1
fi
# shellcheck disable=SC1090
set -a; . "${CONFIG_FILE}"; set +a
: "${SVN_REPO:?SVN_REPO missing in svn-config.cfg}"
: "${SVN_USERNAME:?SVN_USERNAME missing in svn-config.cfg}"
: "${SVN_PASSWORD:?SVN_PASSWORD missing in svn-config.cfg}"
SVN_URL="https://plugins.svn.wordpress.org/${SVN_REPO}"

# ---------- pre-flight ----------
step "Pre-flight checks"

# Git working tree must be clean (unless overridden).
if [[ ${ALLOW_DIRTY} -eq 0 ]]; then
    if ! git diff --quiet || ! git diff --cached --quiet; then
        err "Git working tree is dirty. Commit/stash or rerun with --allow-dirty."
        git status --short >&2
        exit 1
    fi
fi

# Extract & compare versions across the three sources of truth.
PHP_VERSION="$(grep -E '^[[:space:]]*\*[[:space:]]*Version:' blocksify.php \
    | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)"
README_VERSION="$(grep -E '^Stable tag:' readme.txt \
    | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)"
PKG_VERSION="$(node -p "require('./package.json').version" 2>/dev/null || true)"

if [[ -z "${PHP_VERSION}" || -z "${README_VERSION}" || -z "${PKG_VERSION}" ]]; then
    err "Could not extract version from one of the sources."
    printf '    blocksify.php : %s\n    readme.txt    : %s\n    package.json  : %s\n' \
        "${PHP_VERSION:-?}" "${README_VERSION:-?}" "${PKG_VERSION:-?}" >&2
    exit 1
fi
if [[ "${PHP_VERSION}" != "${README_VERSION}" || "${PHP_VERSION}" != "${PKG_VERSION}" ]]; then
    err "Version mismatch across sources:"
    printf '    blocksify.php : %s\n    readme.txt    : %s\n    package.json  : %s\n' \
        "${PHP_VERSION}" "${README_VERSION}" "${PKG_VERSION}" >&2
    exit 1
fi
VERSION="${PHP_VERSION}"
ok "Version: ${VERSION}"

# ---------- composer ----------
if [[ ${SKIP_COMPOSER} -eq 0 ]]; then
    step "Installing Composer dependencies (--no-dev --optimize-autoloader)"
    if ! command -v composer >/dev/null 2>&1; then
        err "composer not found in PATH. Install it or rerun with --skip-composer."
        exit 1
    fi
    composer install --no-dev --optimize-autoloader --no-interaction --no-progress
    ok "Composer dependencies installed"
else
    warn "Skipping composer install (--skip-composer)"
fi

# ---------- build ----------
if [[ ${SKIP_BUILD} -eq 0 ]]; then
    step "Building production assets (npm run build)"
    npm run build
    ok "Build complete"
else
    warn "Skipping build (--skip-build)"
fi

# ---------- SVN working copy ----------
step "Preparing SVN working copy at ${SVN_DIR}"
if [[ ! -d "${SVN_DIR}/.svn" ]]; then
    # First-time checkout: pull only the three top-level dirs (trunk, tags, assets) as empty shells.
    svn checkout --depth=immediates "${SVN_URL}" "${SVN_DIR}"
fi
# Hydrate the dirs we will write into.
svn update --set-depth=infinity "${SVN_DIR}/trunk"
svn update --set-depth=infinity "${SVN_DIR}/assets"
# tags/ stays at --depth=immediates; we only add one new tag locally below.
ok "Working copy ready"

# ---------- sync trunk ----------
step "Syncing source to trunk (rsync, .svnignore as exclude list)"
rsync -rc --delete --delete-excluded \
    --exclude='.svn/' \
    --exclude-from="${PLUGIN_DIR}/.svnignore" \
    "${PLUGIN_DIR}/" "${SVN_DIR}/trunk/"
ok "Trunk synced"

# ---------- sync wp.org assets ----------
# Only banner-*, icon-*, screenshot-* go to SVN /assets/.
# assets/dashboard/ stays under trunk/ because it's runtime UI.
step "Syncing wp.org plugin-page assets (banner / icon / screenshot)"
rsync -rc --delete \
    --include='banner-*' --include='icon-*' --include='screenshot-*' \
    --exclude='*' \
    "${PLUGIN_DIR}/assets/" "${SVN_DIR}/assets/"
ok "Assets synced"

# ---------- sync tag (always) ----------
# Version comes from package.json. The script never modifies the version, but
# it always pushes source into tags/${VERSION}:
#   - If the tag exists on SVN, hydrate it into the working copy and rsync.
#   - If it doesn't exist, mkdir the dir and rsync into it; svn add picks it up
#     in the reconciliation step below.
TAG_WC="${SVN_DIR}/tags/${VERSION}"
if svn info "${SVN_URL}/tags/${VERSION}" >/dev/null 2>&1; then
    step "Updating existing tag ${VERSION}"
    svn update --set-depth=infinity "${TAG_WC}"
    TAG_ACTION="updated"
else
    step "Creating new tag ${VERSION}"
    mkdir -p "${TAG_WC}"
    TAG_ACTION="created"
fi
rsync -rc --delete --delete-excluded \
    --exclude='.svn/' \
    --exclude-from="${PLUGIN_DIR}/.svnignore" \
    "${PLUGIN_DIR}/" "${TAG_WC}/"
ok "Tag ${VERSION} ${TAG_ACTION}"

# ---------- reconcile svn status ----------
# Run after trunk + assets + (optional) tag sync so a single pass covers all dirs.
step "Reconciling svn add / rm"
(
    cd "${SVN_DIR}"
    # Add anything new (rsync already filtered out what we don't want).
    svn add . --force >/dev/null
    # Delete entries that rsync removed locally (svn status flags them with '!').
    svn status | sed -n 's/^! *//p' | while IFS= read -r missing; do
        [[ -n "$missing" ]] && svn rm "$missing" >/dev/null
    done
)

# ---------- status preview ----------
step "Final svn status preview"
( cd "${SVN_DIR}" && svn status )

# ---------- commit ----------
if [[ ${DRY_RUN} -eq 1 ]]; then
    warn "Dry-run mode — skipping svn commit."
    echo "    Inspect the working copy at: ${SVN_DIR}"
    exit 0
fi

step "Committing to wp.org SVN"
svn commit "${SVN_DIR}" \
    -m "Release ${VERSION} (trunk + tags/${VERSION} ${TAG_ACTION})" \
    --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" \
    --no-auth-cache --non-interactive

ok "Deployed v${VERSION}"
printf '\n  Plugin page : https://wordpress.org/plugins/%s/\n' "${SVN_REPO}"
printf '  Tag         : %s/tags/%s/ (%s)\n' "${SVN_URL}" "${VERSION}" "${TAG_ACTION}"
printf '  Working copy retained at: %s\n' "${SVN_DIR}"
