#!/bin/bash

# Laravel Timebank Complete Restoration Script
# Restores both database and storage from backups
# Usage: ./restore-all.sh [options]

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 [options]"
    echo ""
    echo "Options:"
    echo "  --latest              - Restore from latest backups"
    echo "  --database-file FILE  - Specify database backup file"
    echo "  --storage-file FILE   - Specify storage backup file"
    echo "  --database-latest     - Use latest database backup only"
    echo "  --storage-latest      - Use latest storage backup only"
    echo "  --confirm             - Skip confirmation prompts"
    echo "  --list-backups        - List available backups"
    echo "  --help                - Show this help message"
    echo ""
    echo "Restore modes:"
    echo "  Complete restore:     Both database and storage"
    echo "  Database only:        --database-file or --database-latest"
    echo "  Storage only:         --storage-file or --storage-latest"
    echo ""
    echo "Examples:"
    echo "  $0 --latest                           # Restore latest database and storage"
    echo "  $0 --database-latest --storage-latest # Same as above"
    echo "  $0 --database-file db.sql.gz --storage-file storage.tar.gz"
    echo "  $0 --list-backups                     # Show available backups"
    echo ""
    exit 0
}

# Function to list available backups
list_backups() {
    log "INFO" "Available backups for restoration:"
    echo ""
    
    if [ ! -d "$BACKUP_ROOT_DIR" ]; then
        log "WARNING" "No backup directory found"
        return 0
    fi
    
    local backup_found=false
    
    # Database backups
    if [ -d "$BACKUP_ROOT_DIR/database" ]; then
        echo -e "${BLUE}Database backups:${NC}"
        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 | head -3))
                if [ ${#backups[@]} -gt 0 ]; then
                    echo -e "  ${backup_type}:"
                    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
                    backup_found=true
                fi
            fi
        done
        echo ""
    fi
    
    # Storage backups
    if [ -d "$BACKUP_ROOT_DIR/storage" ]; then
        echo -e "${BLUE}Storage backups:${NC}"
        for backup_type in daily weekly monthly; do
            local backup_dir="$BACKUP_ROOT_DIR/storage/$backup_type"
            if [ -d "$backup_dir" ]; then
                local backups=($(find "$backup_dir" -name "*.tar.gz" -type f | sort -r | head -3))
                if [ ${#backups[@]} -gt 0 ]; then
                    echo -e "  ${backup_type}:"
                    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
                    backup_found=true
                fi
            fi
        done
        echo ""
    fi
    
    if [ "$backup_found" = false ]; then
        log "WARNING" "No backups found"
    fi
}

# Function to find latest backup
get_latest_backup() {
    local backup_type="$1"  # database or storage
    local extension="$2"    # sql.gz or tar.gz
    local latest_backup=""
    local latest_time=0
    
    if [ -d "$BACKUP_ROOT_DIR/$backup_type" ]; 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/$backup_type" -name "*.$extension" -type f -print0)
    fi
    
    echo "$latest_backup"
}

# Function to confirm restoration
confirm_restore() {
    local db_file="$1"
    local storage_file="$2"
    
    echo ""
    echo -e "${YELLOW}WARNING: This will REPLACE current data!${NC}"
    echo ""
    
    if [ -n "$db_file" ]; then
        echo -e "${RED}Database restore:${NC}"
        echo -e "  File: $(basename "$db_file")"
        echo -e "  Size: $(du -h "$db_file" | cut -f1)"
        echo -e "  Date: $(date -r "$db_file" '+%Y-%m-%d %H:%M:%S')"
        echo ""
    fi
    
    if [ -n "$storage_file" ]; then
        echo -e "${RED}Storage restore:${NC}"
        echo -e "  File: $(basename "$storage_file")"
        echo -e "  Size: $(du -h "$storage_file" | cut -f1)"
        echo -e "  Date: $(date -r "$storage_file" '+%Y-%m-%d %H:%M:%S')"
        echo ""
    fi
    
    read -p "Are you sure you want to continue? [y/N]: " -n 1 -r
    echo ""
    
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log "INFO" "Restoration cancelled by user"
        exit 0
    fi
}

# Function to validate backup files
validate_backup_file() {
    local file="$1"
    local type="$2"
    
    if [ ! -f "$file" ] || [ ! -r "$file" ]; then
        log "ERROR" "$type backup file not found or not readable: $file"
        return 1
    fi
    
    # Test if backup file is valid
    case "$type" in
        "database")
            if ! gzip -t "$file" 2>/dev/null; then
                log "ERROR" "Database backup file is corrupted or not a valid gzip file"
                return 1
            fi
            ;;
        "storage")
            if ! tar -tzf "$file" >/dev/null 2>&1; then
                log "ERROR" "Storage backup file is corrupted or not a valid tar.gz file"
                return 1
            fi
            ;;
    esac
    
    return 0
}

# Function to restore database
restore_database() {
    local db_file="$1"
    
    log "INFO" "Starting database restoration..."
    
    if ! validate_backup_file "$db_file" "database"; then
        return 1
    fi
    
    # Use the database restore script
    if [ -x "$SCRIPT_DIR/restore-database.sh" ]; then
        log "INFO" "Using database restore script"
        if "$SCRIPT_DIR/restore-database.sh" "$db_file" --confirm; then
            log "SUCCESS" "Database restoration completed"
            return 0
        else
            log "ERROR" "Database restoration failed"
            return 1
        fi
    else
        log "ERROR" "Database restore script not found or not executable"
        return 1
    fi
}

# Function to restore storage
restore_storage() {
    local storage_file="$1"
    
    log "INFO" "Starting storage restoration..."
    
    if ! validate_backup_file "$storage_file" "storage"; then
        return 1
    fi
    
    # Use the storage restore script
    if [ -x "$SCRIPT_DIR/restore-storage.sh" ]; then
        log "INFO" "Using storage restore script"
        if "$SCRIPT_DIR/restore-storage.sh" "$storage_file" --confirm; then
            log "SUCCESS" "Storage restoration completed"
            return 0
        else
            log "ERROR" "Storage restoration failed"
            return 1
        fi
    else
        log "ERROR" "Storage restore script not found or not executable"
        return 1
    fi
}

# Function to perform post-restore tasks
post_restore_tasks() {
    log "INFO" "Running post-restore tasks..."
    
    # Laravel optimization commands
    if [ -f "$PROJECT_ROOT/artisan" ]; then
        log "INFO" "Running Laravel optimization commands..."
        
        # Change to project directory
        cd "$PROJECT_ROOT"
        
        # Clear caches
        php artisan config:clear 2>/dev/null || true
        php artisan cache:clear 2>/dev/null || true
        php artisan view:clear 2>/dev/null || true
        php artisan route:clear 2>/dev/null || true
        
        # Check migration status
        log "INFO" "Checking database migration status..."
        php artisan migrate:status 2>/dev/null || log "WARNING" "Could not check migration status"
        
        log "SUCCESS" "Laravel optimization completed"
    else
        log "WARNING" "Laravel artisan not found, skipping optimization"
    fi
}

# Parse command line arguments
DATABASE_FILE=""
STORAGE_FILE=""
DATABASE_LATEST=false
STORAGE_LATEST=false
LATEST=false
CONFIRM=false
LIST_BACKUPS=false

while [[ $# -gt 0 ]]; do
    case $1 in
        --database-file)
            DATABASE_FILE="$2"
            shift 2
            ;;
        --storage-file)
            STORAGE_FILE="$2"
            shift 2
            ;;
        --database-latest)
            DATABASE_LATEST=true
            shift
            ;;
        --storage-latest)
            STORAGE_LATEST=true
            shift
            ;;
        --latest)
            LATEST=true
            shift
            ;;
        --confirm)
            CONFIRM=true
            shift
            ;;
        --list-backups)
            LIST_BACKUPS=true
            shift
            ;;
        --help)
            show_usage
            ;;
        *)
            log "ERROR" "Unknown option: $1"
            show_usage
            ;;
    esac
done

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

# Handle latest option
if [ "$LATEST" = true ]; then
    DATABASE_LATEST=true
    STORAGE_LATEST=true
fi

# Determine backup files
if [ "$DATABASE_LATEST" = true ]; then
    DATABASE_FILE=$(get_latest_backup "database" "sql.gz")
    if [ -z "$DATABASE_FILE" ]; then
        log "ERROR" "No database backups found"
        exit 1
    fi
    log "INFO" "Using latest database backup: $(basename "$DATABASE_FILE")"
fi

if [ "$STORAGE_LATEST" = true ]; then
    STORAGE_FILE=$(get_latest_backup "storage" "tar.gz")
    if [ -z "$STORAGE_FILE" ]; then
        log "ERROR" "No storage backups found"
        exit 1
    fi
    log "INFO" "Using latest storage backup: $(basename "$STORAGE_FILE")"
fi

# Validate that at least one restoration is requested
if [ -z "$DATABASE_FILE" ] && [ -z "$STORAGE_FILE" ]; then
    log "ERROR" "No restoration specified. Use --help for usage information."
    exit 1
fi

# Resolve relative paths
if [ -n "$DATABASE_FILE" ] && [[ "$DATABASE_FILE" != /* ]]; then
    if [ -f "$BACKUP_ROOT_DIR/$DATABASE_FILE" ]; then
        DATABASE_FILE="$BACKUP_ROOT_DIR/$DATABASE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/daily/$DATABASE_FILE" ]; then
        DATABASE_FILE="$BACKUP_ROOT_DIR/database/daily/$DATABASE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/weekly/$DATABASE_FILE" ]; then
        DATABASE_FILE="$BACKUP_ROOT_DIR/database/weekly/$DATABASE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/database/monthly/$DATABASE_FILE" ]; then
        DATABASE_FILE="$BACKUP_ROOT_DIR/database/monthly/$DATABASE_FILE"
    elif [ -f "$DATABASE_FILE" ]; then
        DATABASE_FILE="$(realpath "$DATABASE_FILE")"
    else
        log "ERROR" "Database backup file not found: $DATABASE_FILE"
        log "INFO" "Checked locations:"
        log "INFO" "  $BACKUP_ROOT_DIR/$DATABASE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/daily/$DATABASE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/weekly/$DATABASE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/database/monthly/$DATABASE_FILE"
        log "INFO" "  ./$DATABASE_FILE"
        exit 1
    fi
fi

if [ -n "$STORAGE_FILE" ] && [[ "$STORAGE_FILE" != /* ]]; then
    if [ -f "$BACKUP_ROOT_DIR/$STORAGE_FILE" ]; then
        STORAGE_FILE="$BACKUP_ROOT_DIR/$STORAGE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/storage/daily/$STORAGE_FILE" ]; then
        STORAGE_FILE="$BACKUP_ROOT_DIR/storage/daily/$STORAGE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/storage/weekly/$STORAGE_FILE" ]; then
        STORAGE_FILE="$BACKUP_ROOT_DIR/storage/weekly/$STORAGE_FILE"
    elif [ -f "$BACKUP_ROOT_DIR/storage/monthly/$STORAGE_FILE" ]; then
        STORAGE_FILE="$BACKUP_ROOT_DIR/storage/monthly/$STORAGE_FILE"
    elif [ -f "$STORAGE_FILE" ]; then
        STORAGE_FILE="$(realpath "$STORAGE_FILE")"
    else
        log "ERROR" "Storage backup file not found: $STORAGE_FILE"
        log "INFO" "Checked locations:"
        log "INFO" "  $BACKUP_ROOT_DIR/$STORAGE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/storage/daily/$STORAGE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/storage/weekly/$STORAGE_FILE"
        log "INFO" "  $BACKUP_ROOT_DIR/storage/monthly/$STORAGE_FILE"
        log "INFO" "  ./$STORAGE_FILE"
        exit 1
    fi
fi

# Main execution
main() {
    log "INFO" "============================================"
    log "INFO" "Starting complete system restoration"
    log "INFO" "Time: $(date)"
    log "INFO" "============================================"
    
    local start_time=$(date +%s)
    local overall_success=true
    
    # Confirm restoration unless --confirm was specified
    if [ "$CONFIRM" = false ]; then
        confirm_restore "$DATABASE_FILE" "$STORAGE_FILE"
    fi
    
    # Restore database
    if [ -n "$DATABASE_FILE" ]; then
        if ! restore_database "$DATABASE_FILE"; then
            overall_success=false
            log "ERROR" "Database restoration failed"
        fi
    else
        log "INFO" "Skipping database restoration (not requested)"
    fi
    
    # Restore storage
    if [ -n "$STORAGE_FILE" ]; then
        if ! restore_storage "$STORAGE_FILE"; then
            overall_success=false
            log "ERROR" "Storage restoration failed"
        fi
    else
        log "INFO" "Skipping storage restoration (not requested)"
    fi
    
    # Post-restore tasks
    if [ "$overall_success" = true ]; then
        post_restore_tasks
        
        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" "Complete system restoration finished in $execution_time_formatted"
        
        # Send notification
        if command -v mail >/dev/null 2>&1; then
            local restored_items=""
            if [ -n "$DATABASE_FILE" ]; then
                restored_items="Database: $(basename "$DATABASE_FILE")"
            fi
            if [ -n "$STORAGE_FILE" ]; then
                if [ -n "$restored_items" ]; then
                    restored_items="$restored_items, Storage: $(basename "$STORAGE_FILE")"
                else
                    restored_items="Storage: $(basename "$STORAGE_FILE")"
                fi
            fi
            echo "Complete system restoration finished successfully at $(date). Restored: $restored_items" | mail -s "Timebank Complete Restore Success" "${BACKUP_NOTIFY_EMAIL:-$USER@localhost}" 2>/dev/null || true
        fi
        
        echo ""
        log "INFO" "Restoration summary:"
        if [ -n "$DATABASE_FILE" ]; then
            log "INFO" "  Database restored from: $(basename "$DATABASE_FILE")"
        fi
        if [ -n "$STORAGE_FILE" ]; then
            log "INFO" "  Storage restored from: $(basename "$STORAGE_FILE")"
        fi
        
        echo ""
        log "INFO" "Recommended next steps:"
        log "INFO" "  1. Test application functionality"
        log "INFO" "  2. Verify file permissions are correct"
        log "INFO" "  3. Check that all services are running properly"
        log "INFO" "  4. Review any Laravel logs for issues"
        
    else
        log "ERROR" "System restoration completed with errors"
        exit 1
    fi
    
    log "INFO" "============================================"
    log "INFO" "Restoration process finished"
    log "INFO" "============================================"
}

# Load environment loader for database credentials (if needed)
if [ -f "$SCRIPT_DIR/load-env.sh" ]; then
    source "$SCRIPT_DIR/load-env.sh"
fi

# Run main function
main