#!/bin/bash

################################################################################
# Plex Media Server Backup Restoration Script
################################################################################
#
# Author: Peter Wood <peter@peterwood.dev>
# Description: Safe and reliable restoration script for Plex Media Server
#              backups with validation, dry-run capability, and automatic
#              backup of current data before restoration.
#
# Features:
#   - Interactive backup selection from available archives
#   - Backup validation before restoration
#   - Dry-run mode for testing restoration process
#   - Automatic backup of current data before restoration
#   - Service management (stop/start Plex during restoration)
#   - Comprehensive logging and error handling
#   - File ownership and permission restoration
#
# Related Scripts:
#   - backup-plex.sh: Creates backups that this script restores
#   - validate-plex-backups.sh: Validates backup integrity
#   - monitor-plex-backup.sh: Monitors backup system health
#   - test-plex-backup.sh: Tests backup/restore operations
#   - plex.sh: General Plex service management
#
# Usage:
#   ./restore-plex.sh                                        # List available backups
#   ./restore-plex.sh plex-backup-20250125_143022.tar.gz    # Restore specific backup
#   ./restore-plex.sh --dry-run backup-file.tar.gz          # Test restoration process
#   ./restore-plex.sh --list                                # List all available backups
#
# Dependencies:
#   - tar (for archive extraction)
#   - Plex Media Server
#   - systemctl (for service management)
#   - Access to backup directory
#
# Exit Codes:
#   0 - Success
#   1 - General error
#   2 - Backup file not found or invalid
#   3 - Service management failure
#   4 - Restoration failure
#
################################################################################

# Plex Backup Restoration Script
# Usage: ./restore-plex.sh [backup_date] [--dry-run]

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# Configuration
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
BACKUP_ROOT="/mnt/share/media/backups/plex"
PLEX_DATA_DIR="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server"

# Plex file locations
declare -A RESTORE_LOCATIONS=(
    ["com.plexapp.plugins.library.db"]="$PLEX_DATA_DIR/Plug-in Support/Databases/"
    ["com.plexapp.plugins.library.blobs.db"]="$PLEX_DATA_DIR/Plug-in Support/Databases/"
    ["Preferences.xml"]="$PLEX_DATA_DIR/"
)

log_message() {
    echo -e "$(date '+%H:%M:%S') $1"
}

log_error() {
    log_message "${RED}ERROR: $1${NC}"
}

log_success() {
    log_message "${GREEN}SUCCESS: $1${NC}"
}

log_warning() {
    log_message "${YELLOW}WARNING: $1${NC}"
}

# List available backups
list_backups() {
    log_message "Available backups:"
    find "$BACKUP_ROOT" -maxdepth 1 -type f -name "plex-backup-*.tar.gz" | sort -r | while read -r backup_file; do
        local backup_name
        backup_name=$(basename "$backup_file")
        local backup_date
        backup_date=${backup_name#plex-backup-}
        backup_date=${backup_date%_*.tar.gz}
        if [[ "$backup_date" =~ ^[0-9]{8}$ ]]; then
            local readable_date
            readable_date=$(date -d "${backup_date:0:4}-${backup_date:4:2}-${backup_date:6:2}" '+%B %d, %Y' 2>/dev/null || echo "Unknown date")
            local file_size
            file_size=$(du -h "$backup_file" 2>/dev/null | cut -f1)
            echo "  $backup_name ($readable_date) - $file_size"
        else
            echo "  $backup_name - $(du -h "$backup_file" 2>/dev/null | cut -f1)"
        fi
    done
}

# Validate backup integrity
validate_backup() {
    local backup_file="$1"

    if [ ! -f "$backup_file" ]; then
        log_error "Backup file not found: $backup_file"
        return 1
    fi

    log_message "Validating backup integrity for $(basename "$backup_file")..."

    # Test archive integrity
    if tar -tzf "$backup_file" >/dev/null 2>&1; then
        log_success "Archive integrity check passed"

        # List contents to verify expected files are present
        log_message "Archive contents:"
        tar -tzf "$backup_file" | while read -r file; do
            log_success "  Found: $file"
        done
        return 0
    else
        log_error "Archive integrity check failed"
        return 1
    fi
}

# Create backup of current Plex data
backup_current_data() {
    local backup_suffix
    backup_suffix=$(date '+%Y%m%d_%H%M%S')
    local current_backup_dir="$SCRIPT_DIR/plex_current_backup_$backup_suffix"

    log_message "Creating backup of current Plex data..."
    mkdir -p "$current_backup_dir"

    for file in "${!RESTORE_LOCATIONS[@]}"; do
        local src="${RESTORE_LOCATIONS[$file]}$file"
        if [ -f "$src" ]; then
            if sudo cp "$src" "$current_backup_dir/"; then
                log_success "Backed up current: $file"
            else
                log_error "Failed to backup current: $file"
                return 1
            fi
        fi
    done

    log_success "Current data backed up to: $current_backup_dir"
    echo "$current_backup_dir"
}

# Restore files from backup
restore_files() {
    local backup_file="$1"
    local dry_run="$2"

    if [ ! -f "$backup_file" ]; then
        log_error "Backup file not found: $backup_file"
        return 1
    fi

    # Create temporary extraction directory
    local temp_dir
    temp_dir="/tmp/plex-restore-$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$temp_dir"

    log_message "Extracting backup archive..."
    if ! tar -xzf "$backup_file" -C "$temp_dir"; then
        log_error "Failed to extract backup archive"
        rm -rf "$temp_dir"
        return 1
    fi

    log_message "Restoring files..."
    local restore_errors=0

    for file in "${!RESTORE_LOCATIONS[@]}"; do
        local src_file="$temp_dir/$file"
        local dest_path="${RESTORE_LOCATIONS[$file]}"
        local dest_file="$dest_path$file"

        if [ -f "$src_file" ]; then
            if [ "$dry_run" == "true" ]; then
                log_message "Would restore: $file to $dest_file"
            else
                log_message "Restoring: $file"
                if sudo cp "$src_file" "$dest_file"; then
                    sudo chown plex:plex "$dest_file"
                    log_success "Restored: $file"
                else
                    log_error "Failed to restore: $file"
                    restore_errors=$((restore_errors + 1))
                fi
            fi
        else
            log_warning "File not found in backup: $file"
            restore_errors=$((restore_errors + 1))
        fi
    done

    # Clean up temporary directory
    rm -rf "$temp_dir"

    return $restore_errors
}

# Manage Plex service
manage_plex_service() {
    local action="$1"
    log_message "$action Plex Media Server..."

    case "$action" in
        "stop")
            sudo systemctl stop plexmediaserver.service
            sleep 3
            log_success "Plex stopped"
            ;;
        "start")
            sudo systemctl start plexmediaserver.service
            sleep 3
            log_success "Plex started"
            ;;
    esac
}

# Main function
main() {
    local backup_file="$1"
    local dry_run=false

    # Check for dry-run flag
    if [ "$2" = "--dry-run" ] || [ "$1" = "--dry-run" ]; then
        dry_run=true
    fi

    # If no backup file provided, list available backups
    if [ -z "$backup_file" ] || [ "$backup_file" = "--dry-run" ]; then
        list_backups
        echo
        echo "Usage: $0 <backup_file> [--dry-run]"
        echo "Example: $0 plex-backup-20250125_143022.tar.gz"
        echo "         $0 /mnt/share/media/backups/plex/plex-backup-20250125_143022.tar.gz"
        exit 0
    fi

    # If relative path, prepend BACKUP_ROOT
    if [[ "$backup_file" != /* ]]; then
        backup_file="$BACKUP_ROOT/$backup_file"
    fi

    # Validate backup exists and is complete
    if ! validate_backup "$backup_file"; then
        log_error "Backup validation failed"
        exit 1
    fi

    if [ "$dry_run" = "true" ]; then
        restore_files "$backup_file" true
        log_message "Dry run completed. No changes were made."
        exit 0
    fi

    # Confirm restoration
    echo
    log_warning "This will restore Plex data from backup $(basename "$backup_file")"
    log_warning "Current Plex data will be backed up before restoration"
    read -p "Continue? (y/N): " -n 1 -r
    echo

    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log_message "Restoration cancelled"
        exit 0
    fi

    # Stop Plex service
    manage_plex_service stop

    # Backup current data
    local current_backup
    if ! current_backup=$(backup_current_data); then
        log_error "Failed to backup current data"
        manage_plex_service start
        exit 1
    fi

    # Restore files
    if restore_files "$backup_file" false; then
        log_success "Restoration completed successfully"
        log_message "Current data backup saved at: $current_backup"
    else
        log_error "Restoration failed"
        manage_plex_service start
        exit 1
    fi

    # Start Plex service
    manage_plex_service start

    log_success "Plex restoration completed. Please verify your server is working correctly."
}

# Trap to ensure Plex is restarted on script exit
trap 'manage_plex_service start' EXIT

main "$@"
