#!/usr/bin/env bash
# release-agent.sh — builds and packages jPOS release archives
# Usage: bash scripts/release-agent.sh <FROM_VERSION> <TO_VERSION> [FROM_TAG] [TO_TAG]
# Example: bash scripts/release-agent.sh 2.1.13 2.1.14 2.1.13 2.1.14
set -euo pipefail

FROM_VERSION="${1:?FROM_VERSION required}"
TO_VERSION="${2:?TO_VERSION required}"
FROM_TAG="${3:-$FROM_VERSION}"
TO_TAG="${4:-$TO_VERSION}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
JPOS_DIR="$PROJECT_ROOT/jpos"
RELEASE_DIR="$PROJECT_ROOT/release"
FULL_STAGING="$RELEASE_DIR/jpos-${TO_VERSION}-full"
UPGRADE_STAGING="$RELEASE_DIR/jpos-${FROM_VERSION}-to-${TO_VERSION}-upgrade"
MIGRATION_SRC="$JPOS_DIR/src/main/resources/db/migration"
INSTALL_OUT="$JPOS_DIR/build/install/jpos"
FULL_ARCHIVE="$RELEASE_DIR/jpos-${TO_VERSION}-full.tar.gz"
UPGRADE_ARCHIVE="$RELEASE_DIR/jpos-${FROM_VERSION}-to-${TO_VERSION}-upgrade.tar.gz"
BUILD_DATE="$(date '+%Y-%m-%d %H:%M:%S')"

log() { echo "[release-agent] $*"; }
section() { echo; echo "══════════════════════════════════════"; echo "  $*"; echo "══════════════════════════════════════"; }

# ── Phase 1: Build ──────────────────────────────────────────────────────────
section "Phase 1: Building jPOS ${TO_VERSION}"
cd "$JPOS_DIR"
log "Running: ./gradlew clean assemble installApp -Ptarget=production"
./gradlew clean assemble installApp -Ptarget=production
log "Build complete. Install output: $INSTALL_OUT"

# ── Phase 2: Detect changes between versions ────────────────────────────────
section "Phase 2: Detecting changes between ${FROM_TAG} and ${TO_TAG}"
cd "$PROJECT_ROOT"

ALL_CHANGED="$(git diff --name-only "${FROM_TAG}" "${TO_TAG}" 2>/dev/null || echo "")"
NEW_MIGRATIONS="$(git diff --name-only "${FROM_TAG}" "${TO_TAG}" -- \
    jpos/src/main/resources/db/migration/ 2>/dev/null | xargs -I{} basename {} 2>/dev/null || echo "")"
CHANGED_CFG="$(git diff --name-only "${FROM_TAG}" "${TO_TAG}" -- \
    jpos/src/dist/cfg/ 2>/dev/null || echo "")"
CHANGED_DEPLOY="$(git diff --name-only "${FROM_TAG}" "${TO_TAG}" -- \
    jpos/src/dist/deploy/ 2>/dev/null || echo "")"
CHANGED_BIN="$(git diff --name-only "${FROM_TAG}" "${TO_TAG}" -- \
    jpos/src/dist/bin/ 2>/dev/null || echo "")"

log "New migrations : $(echo "$NEW_MIGRATIONS" | grep -c . || echo 0)"
log "Changed cfg    : $(echo "$CHANGED_CFG"    | grep -c . || echo 0)"
log "Changed deploy : $(echo "$CHANGED_DEPLOY" | grep -c . || echo 0)"

# ── Phase 3: Clean and create staging directories ────────────────────────────
section "Phase 3: Staging directories"
rm -rf "$FULL_STAGING" "$UPGRADE_STAGING"
mkdir -p "$FULL_STAGING/db/migrations"
mkdir -p "$UPGRADE_STAGING/db/migrations"
mkdir -p "$RELEASE_DIR"

# ── Phase 4: Full archive — copy complete installation ──────────────────────
section "Phase 4: Building full archive"
log "Copying installation from $INSTALL_OUT"
cp -r "$INSTALL_OUT/bin"    "$FULL_STAGING/"
cp -r "$INSTALL_OUT/cfg"    "$FULL_STAGING/"
cp -r "$INSTALL_OUT/deploy" "$FULL_STAGING/"
cp -r "$INSTALL_OUT/lib"    "$FULL_STAGING/"
mkdir -p "$FULL_STAGING/log"

# Remove sensitive files that should never ship
find "$FULL_STAGING" \( \
    -name "*.lmk" -o -name "*.jks" -o -name "*.ks" -o \
    -name "*.ser" -o -name "authorized_keys" \
    \) -delete

# All migrations for fresh schema
cp "$MIGRATION_SRC"/*.sql "$FULL_STAGING/db/migrations/"
log "Copied $(ls "$FULL_STAGING/db/migrations/" | wc -l) migration files (full schema)"

# Generate install.sh
cat > "$FULL_STAGING/install.sh" << INSTALL_EOF
#!/usr/bin/env bash
# install.sh — Fresh deployment of jPOS ${TO_VERSION} on Linux
set -euo pipefail

INSTALL_DIR="\${1:-/opt/jpos}"

echo "=== Installing jPOS ${TO_VERSION} to \$INSTALL_DIR ==="
echo "    Build date: ${BUILD_DATE}"
echo

if [ -d "\$INSTALL_DIR" ]; then
    read -rp "Directory \$INSTALL_DIR already exists. Continue? [y/N] " confirm
    [[ "\$confirm" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
fi

mkdir -p "\$INSTALL_DIR"
cp -r bin cfg deploy lib log "\$INSTALL_DIR/"
chmod +x "\$INSTALL_DIR/bin/"*

echo
echo "=== Database Setup ==="
echo "Apply ALL migration files in the following order before starting jPOS:"
echo
ls -1 db/migrations/
echo
echo "Example:"
echo "  mysql -u <user> -p <database> < db/migrations/000_fix_pos_failed_transaction_id.sql"
echo "  mysql -u <user> -p <database> < db/migrations/001_create_acquirer_terminal_stan_table.sql"
echo "  (continue for each file in order)"
echo
echo "=== Start jPOS ==="
echo "  \$INSTALL_DIR/bin/start"
echo
echo "Done. jPOS ${TO_VERSION} installed to \$INSTALL_DIR"
INSTALL_EOF
chmod +x "$FULL_STAGING/install.sh"

# ── Phase 5: Upgrade archive — only changed files ────────────────────────────
section "Phase 5: Building upgrade archive"

# Always include the new JAR
mkdir -p "$UPGRADE_STAGING/lib"
JAR_FILE="$INSTALL_OUT/lib/jpos-${TO_VERSION}-q2.jar"
if [ -f "$JAR_FILE" ]; then
    cp "$JAR_FILE" "$UPGRADE_STAGING/lib/"
    log "Copied main JAR: jpos-${TO_VERSION}-q2.jar"
else
    # Fallback: find any jpos-*-q2.jar in the lib dir
    FOUND_JAR="$(find "$INSTALL_OUT/lib" -name "jpos-*-q2.jar" | head -1)"
    if [ -n "$FOUND_JAR" ]; then
        cp "$FOUND_JAR" "$UPGRADE_STAGING/lib/"
        log "Copied main JAR: $(basename "$FOUND_JAR")"
    else
        log "WARNING: main JAR not found in $INSTALL_OUT/lib"
    fi
fi

# Changed cfg files
if [ -n "$CHANGED_CFG" ]; then
    mkdir -p "$UPGRADE_STAGING/cfg"
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        rel="${f#jpos/src/dist/cfg/}"
        src="$INSTALL_OUT/cfg/$rel"
        dst="$UPGRADE_STAGING/cfg/$rel"
        mkdir -p "$(dirname "$dst")"
        [ -f "$src" ] && cp "$src" "$dst" && log "cfg: $rel"
    done <<< "$CHANGED_CFG"
fi

# Changed deploy XMLs
if [ -n "$CHANGED_DEPLOY" ]; then
    mkdir -p "$UPGRADE_STAGING/deploy"
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        rel="${f#jpos/src/dist/deploy/}"
        src="$INSTALL_OUT/deploy/$rel"
        dst="$UPGRADE_STAGING/deploy/$rel"
        mkdir -p "$(dirname "$dst")"
        [ -f "$src" ] && cp "$src" "$dst" && log "deploy: $rel"
    done <<< "$CHANGED_DEPLOY"
fi

# Changed bin scripts
if [ -n "$CHANGED_BIN" ]; then
    mkdir -p "$UPGRADE_STAGING/bin"
    while IFS= read -r f; do
        [ -z "$f" ] && continue
        rel="${f#jpos/src/dist/bin/}"
        src="$INSTALL_OUT/bin/$rel"
        dst="$UPGRADE_STAGING/bin/$rel"
        [ -f "$src" ] && cp "$src" "$dst" && chmod +x "$dst" && log "bin: $rel"
    done <<< "$CHANGED_BIN"
fi

# Only NEW migration files
MIGRATION_LIST=""
if [ -n "$NEW_MIGRATIONS" ]; then
    while IFS= read -r fname; do
        [ -z "$fname" ] && continue
        src="$MIGRATION_SRC/$fname"
        [ -f "$src" ] && cp "$src" "$UPGRADE_STAGING/db/migrations/" && \
            log "migration: $fname" && MIGRATION_LIST="$MIGRATION_LIST\n  $fname"
    done <<< "$NEW_MIGRATIONS"
fi

NEW_MIGRATION_COUNT="$(ls "$UPGRADE_STAGING/db/migrations/" 2>/dev/null | wc -l)"
log "Upgrade archive: $NEW_MIGRATION_COUNT new migration(s)"

# Remove sensitive files
find "$UPGRADE_STAGING" \( \
    -name "*.lmk" -o -name "*.jks" -o -name "*.ks" -o \
    -name "*.ser" -o -name "authorized_keys" \
    \) -delete

# Generate upgrade.sh
cat > "$UPGRADE_STAGING/upgrade.sh" << UPGRADE_EOF
#!/usr/bin/env bash
# upgrade.sh — In-place upgrade of jPOS ${FROM_VERSION} → ${TO_VERSION}
set -euo pipefail

INSTALL_DIR="\${1:-/opt/jpos}"
BACKUP_DIR="\$(dirname "\$INSTALL_DIR")/jpos-backup-\$(date +%Y%m%d%H%M%S)"

echo "=== Upgrading jPOS ${FROM_VERSION} → ${TO_VERSION} ==="
echo "    Build date: ${BUILD_DATE}"
echo

if [ ! -d "\$INSTALL_DIR" ]; then
    echo "ERROR: Installation directory not found: \$INSTALL_DIR"
    echo "       For a fresh installation, use the full archive and install.sh instead."
    exit 1
fi

echo "--- Stopping jPOS..."
"\$INSTALL_DIR/bin/stop" 2>/dev/null || true
sleep 2

echo "--- Backing up \$INSTALL_DIR → \$BACKUP_DIR..."
cp -r "\$INSTALL_DIR" "\$BACKUP_DIR"
echo "    Backup created at \$BACKUP_DIR"

echo "--- Copying updated files..."
for dir in bin cfg deploy lib; do
    if [ -d "\$dir" ]; then
        mkdir -p "\$INSTALL_DIR/\$dir"
        cp -r "\$dir/." "\$INSTALL_DIR/\$dir/"
        echo "    Updated: \$dir/"
    fi
done
chmod +x "\$INSTALL_DIR/bin/"* 2>/dev/null || true

echo
echo "=== Database Migrations ==="
MIGRATION_COUNT="\$(ls db/migrations/ 2>/dev/null | wc -l)"
if [ "\$MIGRATION_COUNT" -eq 0 ]; then
    echo "No new migrations for this upgrade."
else
    echo "Apply the following NEW migration(s) in order against your MySQL database"
    echo "BEFORE starting jPOS:"
    echo
    ls -1 db/migrations/
    echo
    echo "Example command:"
    echo "  mysql -h <host> -u <user> -p <database> < db/migrations/<file>.sql"
    echo
    echo "IMPORTANT: Apply all migrations before running bin/start"
fi

echo
echo "=== Start jPOS ==="
echo "After applying migrations:"
echo "  \$INSTALL_DIR/bin/start"
echo
echo "If anything goes wrong, restore from backup:"
echo "  rm -rf \$INSTALL_DIR && cp -r \$BACKUP_DIR \$INSTALL_DIR && \$INSTALL_DIR/bin/start"
UPGRADE_EOF
chmod +x "$UPGRADE_STAGING/upgrade.sh"

# ── Phase 6: Generate RELEASE_NOTES.md and UPGRADE_NOTES.md ─────────────────
section "Phase 6: Generating release notes"

COMMIT_LOG="$(git log "${FROM_TAG}..${TO_TAG}" --oneline 2>/dev/null || echo "(git log unavailable)")"
ALL_SQL="$(ls "$FULL_STAGING/db/migrations/" 2>/dev/null | sort)"
NEW_SQL="$(ls "$UPGRADE_STAGING/db/migrations/" 2>/dev/null | sort || echo "(none)")"

cat > "$FULL_STAGING/RELEASE_NOTES.md" << EOF
# jPOS ${TO_VERSION} — Release Notes (Full Deployment)

**Release date:** ${BUILD_DATE}
**Replaces:** ${FROM_VERSION}

## Changes in this Release

\`\`\`
${COMMIT_LOG}
\`\`\`

## Database Schema

All migrations are included for a complete fresh schema:

$(echo "$ALL_SQL" | awk '{print "- `"$0"`"}')

Apply them in filename order before starting jPOS.

## Installation

\`\`\`bash
# On your Linux server:
tar -xzf jpos-${TO_VERSION}-full.tar.gz
cd jpos-${TO_VERSION}-full/
bash install.sh /opt/jpos
\`\`\`

## Archive Contents

| Directory | Contents |
|-----------|----------|
| \`bin/\` | Startup scripts (q2, start, stop, bsh) |
| \`cfg/\` | Configuration files and packager XMLs |
| \`deploy/\` | Q2 service descriptor XMLs |
| \`lib/\` | jpos-${TO_VERSION}-q2.jar and all runtime dependencies |
| \`log/\` | Empty log directory |
| \`db/migrations/\` | Complete database schema SQL files |
EOF

cat > "$UPGRADE_STAGING/UPGRADE_NOTES.md" << EOF
# jPOS ${FROM_VERSION} → ${TO_VERSION} — Upgrade Notes

**Release date:** ${BUILD_DATE}
**Upgrade path:** ${FROM_VERSION} → ${TO_VERSION}

## Changes in this Release

\`\`\`
${COMMIT_LOG}
\`\`\`

## New Database Migrations

$(if [ "$NEW_MIGRATION_COUNT" -eq 0 ]; then
    echo "No new migrations in this upgrade."
else
    echo "Apply these migrations in order **before** starting jPOS:"
    echo
    echo "$NEW_SQL" | awk '{print "- `"$0"`"}'
fi)

## Upgrade Steps

\`\`\`bash
# On your Linux server:
tar -xzf jpos-${FROM_VERSION}-to-${TO_VERSION}-upgrade.tar.gz
cd jpos-${FROM_VERSION}-to-${TO_VERSION}-upgrade/

# 1. Apply migrations (if any):
mysql -h <host> -u <user> -p <database> < db/migrations/<file>.sql

# 2. Run upgrade script:
bash upgrade.sh /opt/jpos
\`\`\`

## What Changed

| Area | Files |
|------|-------|
| JAR | jpos-${TO_VERSION}-q2.jar |
| Configs | $(echo "$CHANGED_CFG" | grep -c . || echo 0) file(s) changed |
| Deploy XMLs | $(echo "$CHANGED_DEPLOY" | grep -c . || echo 0) file(s) changed |
| DB migrations | ${NEW_MIGRATION_COUNT} new file(s) |
EOF

# ── Phase 7: Create tar.gz archives ─────────────────────────────────────────
section "Phase 7: Creating archives"
cd "$RELEASE_DIR"

log "Creating full archive: $FULL_ARCHIVE"
tar -czf "$FULL_ARCHIVE" "jpos-${TO_VERSION}-full/"
log "Creating upgrade archive: $UPGRADE_ARCHIVE"
tar -czf "$UPGRADE_ARCHIVE" "jpos-${FROM_VERSION}-to-${TO_VERSION}-upgrade/"

# ── Done ─────────────────────────────────────────────────────────────────────
section "Release archives ready"
echo
echo "  FULL (fresh deployment):"
ls -lh "$FULL_ARCHIVE"
echo
echo "  UPGRADE (${FROM_VERSION} → ${TO_VERSION}):"
ls -lh "$UPGRADE_ARCHIVE"
echo
echo "Full archive contents:"
tar -tzf "$FULL_ARCHIVE" | grep -E "^jpos-[^/]+/(bin|cfg|deploy|lib|db|install|RELEASE)/?" | head -20
echo
echo "Upgrade archive contents:"
tar -tzf "$UPGRADE_ARCHIVE" | grep -E "^jpos-[^/]+-[^/]+/(lib|cfg|deploy|bin|db|upgrade|UPGRADE)/" | head -20
