#!/bin/bash
#
# Post-push release pipeline for infrastructure
#
# Architecture:
#   infrastructure/          <- development work (may have uncommitted changes)
#   infrastructure-release/  <- clean clone for deploys
#
# Flow:
#   1. git push on infrastructure main (already done)
#   2. cd infrastructure-release && git pull (gets only committed code)
#   3. Increment version, create tag
#   4. Run reconciliation for changed components
#   5. Push tags to gitlab
#
# This ensures only COMMITTED infrastructure code gets deployed.
#
# Usage:
#   ./post-push              # Run full pipeline
#   ./post-push --dry-run    # Show what would happen
#

set -e

# Parse arguments
DRY_RUN=false
if [[ "$1" == "--dry-run" ]] || [[ "$1" == "-n" ]]; then
    DRY_RUN=true
fi

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
INFRA_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PLATFORM_ROOT="$(cd "$INFRA_ROOT/.." && pwd)"
RELEASES_ROOT="$PLATFORM_ROOT/infrastructure-release"
# Run reconciliation from clean clone (infrastructure-release), not development
RECONCILE="$RELEASES_ROOT/reconciliation/reconcile"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'

log_header() { echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; echo -e "${CYAN}  $1${NC}"; echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; }
log_step() { echo -e "\n${BLUE}▶${NC} $1"; }
log_info() { echo -e "  ${BLUE}ℹ${NC} $1"; }
log_success() { echo -e "  ${GREEN}✓${NC} $1"; }
log_warn() { echo -e "  ${YELLOW}⚠${NC} $1"; }
log_error() { echo -e "  ${RED}✗${NC} $1"; }
log_dry() { echo -e "  ${MAGENTA}[DRY-RUN]${NC} $1"; }

# Wrapper for commands that should be skipped in dry-run
run_cmd() {
    if [[ "$DRY_RUN" == "true" ]]; then
        log_dry "Would run: $*"
        return 0
    fi
    "$@"
}

if [[ "$DRY_RUN" == "true" ]]; then
    log_header "Infrastructure Release Pipeline (DRY RUN)"
    log_warn "DRY RUN MODE - No changes will be made"
else
    log_header "Infrastructure Release Pipeline"
fi

# =============================================================================
# STEP 0: Verify infrastructure-release exists
# =============================================================================
if [[ ! -d "$RELEASES_ROOT" ]]; then
    log_error "infrastructure-release/ not found at: $RELEASES_ROOT"
    log_info "Create it with: git clone infrastructure infrastructure-release"
    exit 1
fi

# =============================================================================
# STEP 1: Pull latest from infrastructure into infrastructure-release
# =============================================================================
log_step "Pulling latest from infrastructure into infrastructure-release..."

cd "$RELEASES_ROOT"
log_info "Working directory: $RELEASES_ROOT"

# Fetch from infrastructure (origin)
run_cmd git fetch origin main

# Show what would be pulled
COMMITS_TO_PULL=$(git log HEAD..origin/main --oneline 2>/dev/null | wc -l)
if [[ "$COMMITS_TO_PULL" -eq 0 ]]; then
    log_info "Already up to date with infrastructure"
else
    log_info "$COMMITS_TO_PULL new commit(s) from infrastructure"
    git log HEAD..origin/main --oneline | head -5
fi

# Pull changes
run_cmd git pull origin main

log_success "Synced with infrastructure"

# =============================================================================
# STEP 2: Increment version and tag
# =============================================================================
log_step "Incrementing version..."

VERSION_FILE="$RELEASES_ROOT/VERSION.json"

if [[ ! -f "$VERSION_FILE" ]]; then
    log_warn "VERSION.json not found, creating..."
    echo '{"major": 0, "merges": 0, "builds": 0, "version": "0.0.0"}' > "$VERSION_FILE"
fi

# Calculate next version
CURRENT_VERSION=$(jq -r '.version' "$VERSION_FILE")
MAJOR=$(jq -r '.major' "$VERSION_FILE")
MERGES=$(jq -r '.merges' "$VERSION_FILE")
BUILDS=$(jq -r '.builds' "$VERSION_FILE")
NEXT_BUILD=$((BUILDS + 1))
NEW_VERSION="$MAJOR.$MERGES.$NEXT_BUILD"

log_info "Current: $CURRENT_VERSION"
log_info "Next:    $NEW_VERSION"

if [[ "$DRY_RUN" != "true" ]]; then
    # Update VERSION.json
    jq --arg v "$NEW_VERSION" \
       --argjson builds "$NEXT_BUILD" \
       --arg lastBuild "$(date -Iseconds)" \
       '.builds = $builds | .version = $v | .lastBuild = $lastBuild' \
       "$VERSION_FILE" > "$VERSION_FILE.tmp" && mv "$VERSION_FILE.tmp" "$VERSION_FILE"

    git add VERSION.json
    git commit -m "build: infra-v$NEW_VERSION

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
    git tag -a "infra-v$NEW_VERSION" -m "Infrastructure Release v$NEW_VERSION"
else
    log_dry "Would increment VERSION.json builds: $NEXT_BUILD"
    log_dry "Would commit version bump"
    log_dry "Would create tag: infra-v$NEW_VERSION"
fi

log_success "Version: infra-v$NEW_VERSION"

# =============================================================================
# STEP 3: Detect and reconcile changed components
# =============================================================================
log_step "Detecting changed components..."

LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
CHANGED_FILES=""

if [[ -n "$LAST_TAG" ]]; then
    CHANGED_FILES=$(git diff --name-only "$LAST_TAG" HEAD 2>/dev/null || echo "")
else
    CHANGED_FILES=$(git diff --name-only HEAD~1 2>/dev/null || echo "")
fi

# Determine what needs reconciliation
RECONCILE_NGINX=false
RECONCILE_SSL=false
RECONCILE_SERVICES=""

if echo "$CHANGED_FILES" | grep -q "^nginx/"; then
    RECONCILE_NGINX=true
    log_info "Detected: nginx config changes"
fi

if echo "$CHANGED_FILES" | grep -q "^reconciliation/services/"; then
    # Extract which services changed
    RECONCILE_SERVICES=$(echo "$CHANGED_FILES" | grep "^reconciliation/services/" | sed 's|reconciliation/services/||' | sed 's|\.sh$||' | sort -u | tr '\n' ' ')
    log_info "Detected: service handler changes: $RECONCILE_SERVICES"
fi

if echo "$CHANGED_FILES" | grep -q "ssl\|certificate"; then
    RECONCILE_SSL=true
    log_info "Detected: SSL/certificate changes"
fi

# Run reconciliation
if [[ "$RECONCILE_NGINX" == "true" ]] || [[ -n "$RECONCILE_SERVICES" ]] || [[ "$RECONCILE_SSL" == "true" ]]; then
    log_step "Running reconciliation..."

    if [[ ! -x "$RECONCILE" ]]; then
        log_error "Reconcile script not found at: $RECONCILE"
        log_warn "Skipping reconciliation"
    else
        # Nginx config sync
        if [[ "$RECONCILE_NGINX" == "true" ]]; then
            log_info "Reconciling nginx configs..."
            run_cmd "$RECONCILE" --host vps --service nginx-config-sync || log_warn "nginx-config-sync failed"
        fi

        # SSL certificates
        if [[ "$RECONCILE_SSL" == "true" ]]; then
            log_info "Reconciling SSL certificates..."
            run_cmd "$RECONCILE" --host vps --service ssl-certificate || log_warn "ssl-certificate failed"
        fi

        # Individual services that changed
        for SERVICE in $RECONCILE_SERVICES; do
            log_info "Reconciling service: $SERVICE..."
            run_cmd "$RECONCILE" --host vps --service "$SERVICE" || log_warn "$SERVICE reconciliation failed"
        done
    fi
else
    log_info "No deployable infrastructure changes detected"
fi

# =============================================================================
# STEP 4: Push tags to gitlab
# =============================================================================
log_step "Pushing to GitLab..."

if git remote | grep -q gitlab; then
    run_cmd git push gitlab main --tags || log_warn "Push to gitlab failed"
    log_success "Pushed to gitlab"
else
    log_warn "No gitlab remote configured"
fi

# =============================================================================
# STEP 5: Sync version back to infrastructure (development)
# =============================================================================
log_step "Syncing version back to infrastructure..."

cd "$INFRA_ROOT"
log_info "Working directory: $INFRA_ROOT"

# Pull the version commit from infrastructure-release
run_cmd git fetch "$RELEASES_ROOT" main
run_cmd git merge FETCH_HEAD --ff-only || {
    log_warn "Could not fast-forward merge, manual sync needed"
    log_info "Run: cd infrastructure && git pull ../infrastructure-release main"
}

log_success "Infrastructure synced with version infra-v$NEW_VERSION"

# =============================================================================
# DONE
# =============================================================================
if [[ "$DRY_RUN" == "true" ]]; then
    log_header "DRY RUN Complete"
    log_info "No changes were made"
    log_info "Run without --dry-run to execute"
else
    log_header "Infrastructure Release infra-v$NEW_VERSION Complete"
    log_info "Infrastructure VERSION.json updated"
    log_info "Tag infra-v$NEW_VERSION created"
fi

exit 0
