#!/bin/bash
#=============================================================================
# Config Migration Manager for ODS
# 
# Handles configuration changes between versions.
# Automatically detects changes and migrates user configs safely.
#
# Usage:
#   ./migrate-config.sh check              # Check if migration needed
#   ./migrate-config.sh migrate            # Run pending migrations
#   ./migrate-config.sh diff               # Show what changed
#   ./migrate-config.sh backup             # Backup current config
#=============================================================================

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="${INSTALL_DIR:-$(dirname "$SCRIPT_DIR")}"
DATA_DIR="${DATA_DIR:-$HOME/.ods}"
BACKUP_DIR="${DATA_DIR}/backups"
# Migrations live in INSTALL_DIR/migrations/ in deployed installs;
# in source tree they live at ods/migrations/ (peer of scripts/).
# SCRIPT_DIR is ods/scripts/ when run from source tree, or
# INSTALL_DIR/scripts/ when run from a deployed install — both resolve correctly.
MIGRATIONS_DIR="${SCRIPT_DIR}/../migrations"
VERSION_FILE="${INSTALL_DIR}/.version"
MIGRATION_STATE="${DATA_DIR}/.migration-state"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# Get current version
get_current_version() {
    if [[ -f "$VERSION_FILE" ]]; then
        if jq -e '.version' "$VERSION_FILE" >/dev/null 2>&1; then
            jq -r '.version' "$VERSION_FILE"
        else
            cat "$VERSION_FILE" | tr -d '[:space:]'
        fi
    else
        echo "0.0.0"
    fi
}

# Get last migrated version
get_last_migrated_version() {
    if [[ -f "$MIGRATION_STATE" ]]; then
        cat "$MIGRATION_STATE" | tr -d '[:space:]'
    else
        echo "0.0.0"
    fi
}

# Set last migrated version
set_last_migrated_version() {
    local version="$1"
    mkdir -p "$(dirname "$MIGRATION_STATE")"
    echo "$version" > "$MIGRATION_STATE"
}

# Compare semantic versions
# Returns: 0 if equal, 1 if v1 > v2, 2 if v1 < v2
compare_versions() {
    local v1="${1#v}"
    local v2="${2#v}"
    
    if [[ "$v1" == "$v2" ]]; then
        return 0
    fi
    
    IFS='.' read -ra V1_PARTS <<< "$v1"
    IFS='.' read -ra V2_PARTS <<< "$v2"
    
    for i in {0..2}; do
        local p1="${V1_PARTS[$i]:-0}"
        local p2="${V2_PARTS[$i]:-0}"
        
        if [[ "$p1" -gt "$p2" ]]; then
            return 1
        elif [[ "$p1" -lt "$p2" ]]; then
            return 2
        fi
    done
    
    return 0
}

# Backup current configuration
cmd_backup() {
    log_info "Backing up current configuration..."
    
    local backup_name backup_path
    backup_name="config-$(date +%Y%m%d-%H%M%S)"
    backup_path="${BACKUP_DIR}/${backup_name}"
    
    mkdir -p "$backup_path"
    
    # Backup key config files
    local cp_exit=0
    cp "${INSTALL_DIR}/.env" "$backup_path/" 2>&1 || cp_exit=$?
    cp "${INSTALL_DIR}/.version" "$backup_path/" 2>&1 || cp_exit=$?
    cp "${INSTALL_DIR}/docker-compose.yml" "$backup_path/" 2>&1 || cp_exit=$?
    cp -r "${INSTALL_DIR}/config" "$backup_path/" 2>&1 || cp_exit=$?

    # Backup user data references
    cp -r "${DATA_DIR}" "$backup_path/data/" 2>&1 || cp_exit=$?
    
    log_success "Configuration backed up to: $backup_path"
    echo "$backup_path"
}

# Show diff between current and example configs
cmd_diff() {
    log_info "Checking for configuration changes..."
    
    local example_env="${INSTALL_DIR}/.env.example"
    local current_env="${INSTALL_DIR}/.env"
    
    if [[ ! -f "$example_env" ]]; then
        log_warn "No .env.example found — cannot show diff"
        return 1
    fi
    
    if [[ ! -f "$current_env" ]]; then
        log_warn "No .env found — user hasn't configured yet"
        return 1
    fi
    
    echo ""
    echo "=== Environment Variable Changes ==="
    echo ""
    
    # Show variables in example but not in current
    echo "New variables (add these to your .env):"
    while IFS='=' read -r key value; do
        [[ -z "$key" || "$key" =~ ^# ]] && continue
        local grep_exit=0
        grep -q "^${key}=" "$current_env" 2>&1 || grep_exit=$?
        if [[ $grep_exit -ne 0 ]]; then
            echo "  + $key=$value"
        fi
    done < "$example_env"

    echo ""
    echo "Deprecated variables (remove from your .env):"
    while IFS='=' read -r key value; do
        [[ -z "$key" || "$key" =~ ^# ]] && continue
        local grep_exit=0
        grep -q "^${key}=" "$example_env" 2>&1 || grep_exit=$?
        if [[ $grep_exit -ne 0 ]]; then
            echo "  - $key"
        fi
    done < "$current_env"
}

# Check if migration is needed
cmd_check() {
    local current_version
    local last_migrated
    
    current_version=$(get_current_version)
    last_migrated=$(get_last_migrated_version)
    
    log_info "Current version: $current_version"
    log_info "Last migrated: $last_migrated"
    
    compare_versions "$current_version" "$last_migrated"
    local result
    result=$?

    if [[ $result -eq 2 ]]; then
        log_warn "Migration needed: $last_migrated → $current_version"
        
        # List pending migrations
        echo ""
        echo "Pending migrations:"
        for migration in "$MIGRATIONS_DIR"/migrate-v*.sh; do
            if [[ -f "$migration" ]]; then
                local migration_version
                migration_version=$(basename "$migration" | sed 's/migrate-v//;s/.sh//')
                
                compare_versions "$migration_version" "$last_migrated"
                if [[ $? -eq 1 ]]; then
                    echo "  - $migration_version: $(head -5 "$migration" | grep '^# Description:' | sed 's/# Description://')"
                fi
            fi
        done
        
        return 2
    else
        log_success "No migration needed (already at $current_version)"
        return 0
    fi
}

# Run pending migrations
cmd_migrate() {
    log_info "Starting configuration migration..."
    
    local current_version
    local last_migrated
    
    current_version=$(get_current_version)
    last_migrated=$(get_last_migrated_version)
    
    # Create backup first
    cmd_backup >/dev/null
    
    compare_versions "$current_version" "$last_migrated"
    if [[ $? -ne 2 ]]; then
        log_success "Already up to date ($current_version)"
        return 0
    fi
    
    log_info "Migrating: $last_migrated → $current_version"
    
    # Run migrations in order
    local failed=0
    local ls_exit=0
    local migrations
    migrations=$(ls -1 "$MIGRATIONS_DIR"/migrate-v*.sh 2>&1 | sort) || ls_exit=$?
    if [[ $ls_exit -ne 0 ]]; then
        log_success "No migration scripts found"
        return 0
    fi

    for migration in $migrations; do
        if [[ -f "$migration" ]]; then
            local migration_version
            migration_version=$(basename "$migration" | sed 's/migrate-v//;s/.sh//')
            
            # Check if this migration is needed
            compare_versions "$migration_version" "$last_migrated"
            if [[ $? -eq 1 ]]; then
                log_info "Running migration: $migration_version"
                
                if bash "$migration"; then
                    log_success "Migration $migration_version completed"
                    set_last_migrated_version "$migration_version"
                else
                    log_error "Migration $migration_version failed!"
                    ((failed++)) || true
                    break
                fi
            fi
        fi
    done
    
    if [[ $failed -eq 0 ]]; then
        set_last_migrated_version "$current_version"
        log_success "Migration complete! Updated to $current_version"
        return 0
    else
        log_error "Migration failed. Check logs and restore from backup."
        return 1
    fi
}

# Validate .env against schema
cmd_validate() {
    local validator="${SCRIPT_DIR}/validate-env.sh"
    local env_file="${INSTALL_DIR}/.env"
    local schema_file="${INSTALL_DIR}/.env.schema.json"

    if [[ ! -f "$validator" ]]; then
        log_error "Validator script missing: $validator"
        return 1
    fi
    if [[ ! -f "$schema_file" ]]; then
        log_error "Schema missing: $schema_file"
        return 1
    fi
    bash "$validator" "$env_file" "$schema_file"
}

# Show help
cmd_help() {
    cat << 'EOF'
ODS Config Migration Manager

Usage: ./migrate-config.sh [command]

Commands:
  check       Check if migration is needed
  migrate     Run pending migrations (with backup)
  diff        Show configuration differences
  backup      Backup current configuration
  validate    Validate .env against .env.schema.json
  help        Show this help message

Examples:
  ./migrate-config.sh check
  ./migrate-config.sh migrate
  ./migrate-config.sh diff
  ./migrate-config.sh validate

Migration scripts should be placed in the migrations/ directory
and named: migrate-vX.Y.Z.sh

EOF
}

# Main
case "${1:-help}" in
    check)
        cmd_check
        ;;
    migrate)
        cmd_migrate
        ;;
    diff)
        cmd_diff
        ;;
    backup)
        cmd_backup
        ;;
    validate)
        cmd_validate
        ;;
    help|--help|-h)
        cmd_help
        ;;
    *)
        log_error "Unknown command: $1"
        cmd_help
        exit 1
        ;;
esac
