#!/bin/bash

# Laravel Timebank Database Restore Script
# Restores MySQL database from compressed backup
# Usage: ./restore-database.sh [backup_file] [options]
# Options: --confirm, --list-backups, --latest

set -e  # Exit on any error

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
BACKUP_ROOT_DIR="$PROJECT_ROOT/backups"
LOG_FILE="$BACKUP_ROOT_DIR/restore.log"

# Create log directory
mkdir -p "$BACKUP_ROOT_DIR/logs"

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

# Logging function
log() {
    local level="$1"
    local message="$2"
    local timestamp="[$(date '+%Y-%m-%d %H:%M:%S')]"
    
    case "$level" in
        "INFO")
            echo -e "${timestamp} ${BLUE}[INFO]${NC} $message" | tee -a "$LOG_FILE"
            ;;
        "SUCCESS")
            echo -e "${timestamp} ${GREEN}[SUCCESS]${NC} $message" | tee -a "$LOG_FILE"
            ;;
        "WARNING")
            echo -e "${timestamp} ${YELLOW}[WARNING]${NC} $message" | tee -a "$LOG_FILE"
            ;;
        "ERROR")
            echo -e "${timestamp} ${RED}[ERROR]${NC} $message" | tee -a "$LOG_FILE"
            ;;
        *)
            echo "$timestamp $message" | tee -a "$LOG_FILE"
            ;;
    esac
}

# Function to show usage
show_usage() {
    echo "Usage: $0 [backup_file] [options]"
    echo ""
    echo "Arguments:"
    echo "  backup_file      - Path to backup file (relative to backup directory or absolute)"
    echo ""
    echo "Options:"
    echo "  --confirm        - Skip confirmation prompt"
    echo "  --list-backups   - List available backups"
    echo "  --latest         - Restore from latest backup"
    echo "  --help           - Show this help message"
    echo ""
    echo "Examples:"
    echo "  $0 --list-backups                           # List available backups"
    echo "  $0 --latest                                 # Restore latest backup"
    echo "  $0 database/daily/mydb_daily_20240101.sql.gz  # Restore specific backup"
    echo ""
    exit 0
}

# Function to list available backups
list_backups() {
    log "INFO" "Available database backups:"
    echo ""
    
    if [ ! -d "$BACKUP_ROOT_DIR/database" ]; then
        log "WARNING" "No backup directory found"
        return 0
    fi
    
    local backup_found=false
    
    for backup_type in daily weekly monthly; do
        local backup_dir="$BACKUP_ROOT_DIR/database/$backup_type"
        if [ -d "$backup_dir" ]; then
            local backups=($(find "$backup_dir" -name "*.sql.gz" -type f | sort -r))
            if [ ${#backups[@]} -gt 0 ]; then
                echo -e "${BLUE}$backup_type backups:${NC}"
                for backup in "${backups[@]}"; do
                    local size=$(du -h "$backup" | cut -f1)
                    local date_created=$(date -r "$backup" '+%Y-%m-%d %H:%M:%S')
                    echo "  $(basename "$backup") ($size, $date_created)"
                done
                echo ""
                backup_found=true
            fi
        fi
    done
    
    if [ "$backup_found" = false ]; then
        log "WARNING" "No database backups found"
    fi
}

# Function to find latest backup
get_latest_backup() {
    local latest_backup=""
    local latest_time=0
    
    if [ -d "$BACKUP_ROOT_DIR/database" ]; then
        while IFS= read -r -d '' backup; do
            local backup_time=$(stat -c %Y "$backup")
            if [ "$backup_time" -gt "$latest_time" ]; then
                latest_time=$backup_time
                latest_backup=$backup
            fi
        done < <(find "$BACKUP_ROOT_DIR/database" -name "*.sql.gz" -type f -print0)
    fi
    
    echo "$latest_backup"
}

# Function to confirm restore
confirm_restore() {
    local backup_file="$1"
    
    echo ""
    echo -e "${YELLOW}WARNING: This will REPLACE the current database!${NC}"
    echo -e "Database: ${RED}$DB_DATABASE${NC}"
    echo -e "Backup file: ${BLUE}$(basename "$backup_file")${NC}"
    echo -e "Backup size: $(du -h "$backup_file" | cut -f1)"
    echo -e "Backup date: $(date -r "$backup_file" '+%Y-%m-%d %H:%M:%S')"
    echo ""
    
    read -p "Are you sure you want to continue? [y/N]: " -n 1 -r
    echo ""
    
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log "INFO" "Restore cancelled by user"
        exit 0
    fi
}

# Function to create database backup before restore
create_pre_restore_backup() {
    log "INFO" "Creating pre-restore backup of current database"
    
    local pre_restore_dir="$BACKUP_ROOT_DIR/database/pre-restore"
    mkdir -p "$pre_restore_dir"
    
    local timestamp=$(date '+%Y%m%d_%H%M%S')
    local backup_file="$pre_restore_dir/${DB_DATABASE}_pre_restore_${timestamp}.sql.gz"
    
    # Use the database backup script if available
    if [ -x "$SCRIPT_DIR/backup-database.sh" ]; then
        log "INFO" "Using backup script for pre-restore backup"
        
        # Create MySQL configuration file for secure password handling
        local mysql_cnf_file="/tmp/mysql_pre_restore_$$.cnf"
        cat > "$mysql_cnf_file" <<EOF
[mysqldump]
host=${DB_HOST:-127.0.0.1}
port=${DB_PORT:-3306}
user=$DB_USERNAME
password=$DB_PASSWORD
EOF
        
        # Set secure permissions on the config file
        chmod 600 "$mysql_cnf_file"
        
        # Create a temporary backup
        mysqldump \
            --defaults-extra-file="$mysql_cnf_file" \
            --single-transaction \
            --routines \
            --triggers \
            --events \
            --add-drop-database \
            --databases "$DB_DATABASE" | gzip > "$backup_file"
        
        # Clean up the temporary config file
        rm -f "$mysql_cnf_file"
        
        if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
            log "SUCCESS" "Pre-restore backup created: $backup_file"
        else
            log "ERROR" "Pre-restore backup failed"
            return 1
        fi
    fi
}

# Function to restore database
restore_database() {
    local backup_file="$1"
    
    log "INFO" "Starting database restore from: $(basename "$backup_file")"
    
    # Verify backup file exists and is readable
    if [ ! -f "$backup_file" ] || [ ! -r "$backup_file" ]; then
        log "ERROR" "Backup file not found or not readable: $backup_file"
        return 1
    fi
    
    # Test if backup file is valid gzip
    if ! gzip -t "$backup_file" 2>/dev/null; then
        log "ERROR" "Backup file is corrupted or not a valid gzip file"
        return 1
    fi
    
    # Extract and restore
    log "INFO" "Decompressing and restoring backup..."
    
    # Create MySQL configuration file for secure password handling
    local mysql_cnf_file="/tmp/mysql_restore_$$.cnf"
    cat > "$mysql_cnf_file" <<EOF
[mysql]
host=${DB_HOST:-127.0.0.1}
port=${DB_PORT:-3306}
user=$DB_USERNAME
password=$DB_PASSWORD
EOF
    
    # Set secure permissions on the config file
    chmod 600 "$mysql_cnf_file"
    
    # Perform the restore using the config file
    if gzip -dc "$backup_file" | mysql --defaults-extra-file="$mysql_cnf_file"; then
        log "SUCCESS" "Database restore completed successfully"
        rm -f "$mysql_cnf_file"
        return 0
    else
        log "ERROR" "Database restore failed"
        rm -f "$mysql_cnf_file"
        return 1
    fi
}

# Parse command line arguments
BACKUP_FILE=""
CONFIRM=false
LIST_BACKUPS=false
LATEST=false

while [[ $# -gt 0 ]]; do
    case $1 in
        --confirm)
            CONFIRM=true
            shift
            ;;
        --list-backups)
            LIST_BACKUPS=true
            shift
            ;;
        --latest)
            LATEST=true
            shift
            ;;
        --help)
            show_usage
            ;;
        -*)
            log "ERROR" "Unknown option: $1"
            show_usage
            ;;
        *)
            if [ -z "$BACKUP_FILE" ]; then
                BACKUP_FILE="$1"
            else
                log "ERROR" "Multiple backup files specified"
                show_usage
            fi
            shift
            ;;
    esac
done

# Load environment loader
source "$SCRIPT_DIR/load-env.sh"

# Load environment variables
if ! load_env "$PROJECT_ROOT/.env"; then
    log "ERROR" ".env file not found in $PROJECT_ROOT"
    exit 1
fi

# Validate required environment variables
if [ -z "$DB_DATABASE" ] || [ -z "$DB_USERNAME" ] || [ -z "$DB_HOST" ]; then
    log "ERROR" "Required database environment variables not found (DB_DATABASE, DB_USERNAME, DB_HOST)"
    exit 1
fi

# Handle list backups option
if [ "$LIST_BACKUPS" = true ]; then
    list_backups
    exit 0
fi

# Handle latest backup option
if [ "$LATEST" = true ]; then
    BACKUP_FILE=$(get_latest_backup)
    if [ -z "$BACKUP_FILE" ]; then
        log "ERROR" "No backups found"
        exit 1
    fi
    log "INFO" "Using latest backup: $(basename "$BACKUP_FILE")"
fi

# Validate backup file argument
if [ -z "$BACKUP_FILE" ]; then
    log "ERROR" "No backup file specified"
    show_usage
fi

# Resolve backup file path
if [[ "$BACKUP_FILE" != /* ]]; then
    # Relative path - check if it exists relative to backup directory
    if [ -f "$BACKUP_ROOT_DIR/$BACKUP_FILE" ]; then
        BACKUP_FILE="$BACKUP_ROOT_DIR/$BACKUP_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/daily/$BACKUP_FILE" ]; then
        BACKUP_FILE="$BACKUP_ROOT_DIR/database/daily/$BACKUP_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/weekly/$BACKUP_FILE" ]; then
        BACKUP_FILE="$BACKUP_ROOT_DIR/database/weekly/$BACKUP_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/monthly/$BACKUP_FILE" ]; then
        BACKUP_FILE="$BACKUP_ROOT_DIR/database/monthly/$BACKUP_FILE"
    elif [ -f "$BACKUP_FILE" ]; then
        # Exists relative to current directory
        BACKUP_FILE="$(realpath "$BACKUP_FILE")"
    else
        log "ERROR" "Database backup file not found: $BACKUP_FILE"
        log "INFO" "Checked locations:"
        log "INFO" "  $BACKUP_ROOT_DIR/$BACKUP_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/daily/$BACKUP_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/weekly/$BACKUP_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/monthly/$BACKUP_FILE"
        log "INFO" "  ./$BACKUP_FILE"
        exit 1
    fi
fi

# Main execution
main() {
    log "INFO" "============================================"
    log "INFO" "Starting database restore process"
    log "INFO" "Time: $(date)"
    log "INFO" "============================================"
    
    local start_time=$(date +%s)
    
    # Confirm restore unless --confirm was specified
    if [ "$CONFIRM" = false ]; then
        confirm_restore "$BACKUP_FILE"
    fi
    
    # Create pre-restore backup
    if ! create_pre_restore_backup; then
        log "WARNING" "Pre-restore backup failed, but continuing with restore"
    fi
    
    # Perform restore
    if restore_database "$BACKUP_FILE"; then
        local end_time=$(date +%s)
        local execution_time=$((end_time - start_time))
        local execution_time_formatted=$(date -d@$execution_time -u +%H:%M:%S)
        
        log "SUCCESS" "Database restore completed successfully in $execution_time_formatted"
        log "INFO" "Restored from: $(basename "$BACKUP_FILE")"
        
        # Send notification
        if command -v mail >/dev/null 2>&1; then
            echo "Database restore completed successfully at $(date). Restored from: $(basename "$BACKUP_FILE")" | mail -s "Timebank DB Restore Success" "${BACKUP_NOTIFY_EMAIL:-$USER@localhost}" 2>/dev/null || true
        fi
        
        # Recommend running Laravel commands
        echo ""
        log "INFO" "Recommended post-restore steps:"
        log "INFO" "  1. php artisan migrate:status"
        log "INFO" "  2. php artisan config:clear"
        log "INFO" "  3. php artisan cache:clear"
        log "INFO" "  4. Test application functionality"
        
    else
        log "ERROR" "Database restore failed"
        exit 1
    fi
    
    log "INFO" "============================================"
    log "INFO" "Restore process finished"
    log "INFO" "============================================"
}

# Run main function
main