#!/bin/bash
set -euo pipefail

#
# release.sh — Publish a new version to WordPress.org SVN
#
# This is the only script needed for the release process. It:
#   1. Syncs plugin files from the Git repo → SVN trunk
#   2. Updates version numbers
#   3. Creates a new SVN tag
#   4. Stages all SVN changes (adds/deletes)
#
# After running, review with `svn diff` and publish with `svn ci`.
#
# Usage:
#   ./release.sh                     # bump patch  (2.0.0 → 2.0.1)
#   ./release.sh --minor             # bump minor  (2.0.0 → 2.1.0)
#   ./release.sh --major             # bump major  (2.0.0 → 3.0.0)
#   ./release.sh --version 2.0.0     # set exact version
#   ./release.sh --dry-run           # preview without changes
#   ./release.sh --dry-run --minor   # combine flags
#

# ─── Configuration ─────────────────────────────────────────────────
# Override the Git repo path:  BNPLX_GIT_REPO=/other/path ./release.sh
GIT_REPO="${BNPLX_GIT_REPO:-$HOME/Workspace/bnplx-payment-gateway-for-woocommerce}"

SVN_DIR="$(cd "$(dirname "$0")" && pwd)"
TRUNK_DIR="$SVN_DIR/trunk"
TAGS_DIR="$SVN_DIR/tags"
MAIN_FILE="bnplx-checkout.php"

# ── Plugin contents whitelist ──────────────────────────────────────
# Only these files/directories are synced to SVN and published.
# Everything else in the Git repo (Docker, dev scripts, etc.) is ignored.
# Update this list when you add new top-level plugin files or directories.
PLUGIN_CONTENTS=(
    "bnplx-checkout.php"
    "readme.txt"
    "includes"
    "languages"
    "assets"
)

# ─── Helpers ───────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'
BLUE='\033[0;34m'; BOLD='\033[1m'; NC='\033[0m'

info()  { echo -e "  ${BLUE}▸${NC} $*"; }
ok()    { echo -e "  ${GREEN}✓${NC} $*"; }
warn()  { echo -e "  ${YELLOW}⚠${NC} $*"; }
err()   { echo -e "  ${RED}✗${NC} $*" >&2; }
step()  { echo -e "\n${BOLD}[$1/5] $2${NC}"; }

# ─── Parse arguments ──────────────────────────────────────────────
BUMP_TYPE="patch"
EXACT_VERSION=""
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case "$1" in
        --major)        BUMP_TYPE="major"; shift ;;
        --minor)        BUMP_TYPE="minor"; shift ;;
        --patch)        BUMP_TYPE="patch"; shift ;;
        --version)      EXACT_VERSION="$2"; shift 2 ;;
        --dry-run)      DRY_RUN=true; shift ;;
        -h|--help)
            sed -n '/^# Usage:/,/^#$/p' "$0" | sed 's/^# \?//'
            exit 0
            ;;
        *)  err "Unknown option: $1"; exit 1 ;;
    esac
done

# ─── Validate ──────────────────────────────────────────────────────
if [[ ! -d "$GIT_REPO/.git" ]]; then
    err "Git repo not found at: $GIT_REPO"
    err "Set BNPLX_GIT_REPO env var or check the path."
    exit 1
fi

if [[ ! -d "$SVN_DIR/.svn" ]]; then
    err "Not an SVN working copy: $SVN_DIR"
    exit 1
fi

if [[ -n "$EXACT_VERSION" && ! "$EXACT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    err "Invalid version: $EXACT_VERSION (expected X.Y.Z)"
    exit 1
fi

# ─── Determine version ────────────────────────────────────────────
CURRENT_VERSION=$(ls "$TAGS_DIR" 2>/dev/null \
    | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
    | sort -V | tail -n 1 || true)

if [[ -z "$CURRENT_VERSION" ]]; then
    CURRENT_VERSION="0.0.0"
    warn "No existing tags — starting from 0.0.0"
fi

if [[ -n "$EXACT_VERSION" ]]; then
    NEW_VERSION="$EXACT_VERSION"
else
    IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
    case "$BUMP_TYPE" in
        major) NEW_VERSION="$((MAJOR + 1)).0.0" ;;
        minor) NEW_VERSION="$MAJOR.$((MINOR + 1)).0" ;;
        patch) NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))" ;;
    esac
fi

if [[ -d "$TAGS_DIR/$NEW_VERSION" ]]; then
    err "Tag $NEW_VERSION already exists!"
    exit 1
fi

# ─── Confirmation ──────────────────────────────────────────────────
echo ""
echo -e "${BOLD}BNPLX Payment Gateway — WordPress.org Release${NC}"
echo ""
echo -e "  Current version:  ${YELLOW}$CURRENT_VERSION${NC}"
echo -e "  New version:      ${GREEN}$NEW_VERSION${NC}"
echo -e "  Git repo:         $GIT_REPO"
echo -e "  SVN working copy: $SVN_DIR"
$DRY_RUN && echo -e "  Mode:             ${YELLOW}DRY RUN${NC}"
echo ""

read -p "  Continue? (y/n): " confirm
if [[ "$confirm" != "y" ]]; then
    echo "  Aborted."
    exit 0
fi

# ─── Step 1: Sync Git → SVN trunk ─────────────────────────────────
step 1 "Syncing plugin files: Git → SVN trunk"

RSYNC_ARGS=(-av --delete --delete-excluded)
$DRY_RUN && RSYNC_ARGS+=(--dry-run)

# Build rsync filter: only include whitelisted plugin contents.
# --delete-excluded removes old dev files from trunk (README.md, scripts, etc.)
# .svn is excluded first so it's protected from deletion.
RSYNC_FILTERS=(--exclude='.svn')
for item in "${PLUGIN_CONTENTS[@]}"; do
    RSYNC_FILTERS+=(--include="$item" --include="$item/***")
done
RSYNC_FILTERS+=(--exclude='*')

rsync "${RSYNC_ARGS[@]}" "${RSYNC_FILTERS[@]}" "$GIT_REPO/" "$TRUNK_DIR/"
ok "Trunk synced"

# ─── Step 2: Update version numbers ───────────────────────────────
step 2 "Updating version → $NEW_VERSION"

if ! $DRY_RUN; then
    sed -i '' -E "s/(Stable tag:[[:space:]]*)[0-9]+\.[0-9]+\.[0-9]+/\1${NEW_VERSION}/" \
        "$TRUNK_DIR/readme.txt"
    ok "trunk/readme.txt  Stable tag: $NEW_VERSION"

    sed -i '' -E "s/(Version:[[:space:]]*)[0-9]+\.[0-9]+\.[0-9]+/\1${NEW_VERSION}/" \
        "$TRUNK_DIR/$MAIN_FILE"
    ok "trunk/$MAIN_FILE  Version: $NEW_VERSION"
else
    info "[dry-run] Would set Stable tag and Version to $NEW_VERSION"
fi

# ─── Step 3: Create SVN tag ───────────────────────────────────────
step 3 "Creating tag: tags/$NEW_VERSION"

if ! $DRY_RUN; then
    mkdir -p "$TAGS_DIR/$NEW_VERSION"

    for item in "${PLUGIN_CONTENTS[@]}"; do
        src="$TRUNK_DIR/$item"
        if [[ -d "$src" ]]; then
            cp -r "$src" "$TAGS_DIR/$NEW_VERSION/"
        elif [[ -f "$src" ]]; then
            cp "$src" "$TAGS_DIR/$NEW_VERSION/"
        else
            warn "Missing in trunk: $item (skipped)"
        fi
    done
    ok "Tag created"
else
    info "[dry-run] Would copy trunk → tags/$NEW_VERSION"
fi

# ─── Step 4: Stage SVN changes ────────────────────────────────────
step 4 "Staging SVN changes"

if ! $DRY_RUN; then
    ADDED=0
    DELETED=0

    # Only stage changes under trunk/ and tags/ (not SVN root files like release.sh)
    # svn add unversioned files (status = ?)
    while IFS= read -r line; do
        file="${line:8}"
        svn add --parents "$file" 2>/dev/null && ADDED=$((ADDED + 1))
    done < <(svn status "$TRUNK_DIR" "$TAGS_DIR" | grep '^?')

    # svn delete missing files (status = !)
    while IFS= read -r line; do
        file="${line:8}"
        svn delete "$file" 2>/dev/null && DELETED=$((DELETED + 1))
    done < <(svn status "$TRUNK_DIR" "$TAGS_DIR" | grep '^!')

    [[ $ADDED -gt 0 ]]   && ok "Added $ADDED new file(s) to SVN"
    [[ $DELETED -gt 0 ]]  && ok "Removed $DELETED deleted file(s) from SVN"
    [[ $ADDED -eq 0 && $DELETED -eq 0 ]] && info "No files to add or remove"
else
    info "[dry-run] Would run svn add/delete for changed files"
fi

# ─── Step 5: Summary ──────────────────────────────────────────────
step 5 "Summary"

echo ""
SVN_STATUS=$(svn status "$TRUNK_DIR" "$TAGS_DIR")
CHANGE_COUNT=$(echo "$SVN_STATUS" | grep -c '^[AMDRC!?]' || true)

if [[ $CHANGE_COUNT -gt 0 ]]; then
    echo "$SVN_STATUS" | head -40
    [[ $CHANGE_COUNT -gt 40 ]] && info "... and $((CHANGE_COUNT - 40)) more (run: svn status)"
fi

echo ""
if $DRY_RUN; then
    echo -e "  ${YELLOW}Dry run complete — no changes were made.${NC}"
    echo -e "  Run without --dry-run to execute."
else
    echo -e "  ${GREEN}${BOLD}Ready to publish v$NEW_VERSION!${NC}"
    echo ""
    echo -e "  Review:   ${BOLD}svn diff${NC}"
    echo -e "  Publish:  ${BOLD}svn ci -m \"Release $NEW_VERSION\"${NC}"
fi
echo ""
