#!/bin/bash

################################################################################
# Consolidated Plex Database Management Script
################################################################################
#
# Author: Peter Wood <peter@peterwood.dev>
# Description: Consolidated database management functionality combining the best
#              features from plex-database-repair.sh, recover-plex-database.sh,
#              and nuclear-plex-recovery.sh into a single, safe interface.
#
# Features:
#   - Read-only integrity checking
#   - Progressive repair strategies (gentle to aggressive)
#   - Service management with proper synchronization
#   - Comprehensive logging and error handling
#   - Manual intervention prompts for safety
#
# Usage:
#   ./plex-db-manager.sh check              # Read-only integrity check
#   ./plex-db-manager.sh repair             # Interactive repair
#   ./plex-db-manager.sh repair --gentle    # Gentle repair only
#   ./plex-db-manager.sh repair --force     # Aggressive repair
#   ./plex-db-manager.sh nuclear            # Nuclear recovery
#
# Exit Codes:
#   0 - Success
#   1 - Database issues detected (no repair attempted)
#   2 - Repair failed
#   3 - Service management failure
#
################################################################################

set -euo pipefail

# Color codes for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly WHITE='\033[1;37m'
readonly BOLD='\033[1m'
readonly DIM='\033[2m'
readonly RESET='\033[0m'

# Configuration
readonly PLEX_SERVICE="plexmediaserver"
readonly PLEX_SQLITE="/usr/lib/plexmediaserver/Plex SQLite"
readonly PLEX_DB_DIR="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases"
readonly MAIN_DB="$PLEX_DB_DIR/com.plexapp.plugins.library.db"
readonly BLOBS_DB="$PLEX_DB_DIR/com.plexapp.plugins.library.blobs.db"
readonly BACKUP_ROOT="/mnt/share/media/backups/plex"

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
readonly SCRIPT_DIR
readonly LOG_FILE="$SCRIPT_DIR/logs/db-manager-$(date +%Y%m%d_%H%M%S).log"

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

# Logging functions
log_message() {
    local message="$1"
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${CYAN}[${timestamp}]${RESET} ${message}"
    echo "[${timestamp}] ${message}" >> "$LOG_FILE" 2>/dev/null || true
}

log_error() {
    local message="$1"
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${RED}[${timestamp}] ERROR:${RESET} ${message}" >&2
    echo "[${timestamp}] ERROR: ${message}" >> "$LOG_FILE" 2>/dev/null || true
}

log_success() {
    local message="$1"
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${GREEN}[${timestamp}] SUCCESS:${RESET} ${message}"
    echo "[${timestamp}] SUCCESS: ${message}" >> "$LOG_FILE" 2>/dev/null || true
}

log_warning() {
    local message="$1"
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${YELLOW}[${timestamp}] WARNING:${RESET} ${message}"
    echo "[${timestamp}] WARNING: ${message}" >> "$LOG_FILE" 2>/dev/null || true
}

# Print header
print_header() {
    echo -e "\n${BOLD}${CYAN}+================================================================+${RESET}"
    echo -e "${BOLD}${CYAN}|              PLEX DATABASE MANAGEMENT TOOL                    |${RESET}"
    echo -e "${BOLD}${CYAN}+================================================================+${RESET}\n"
}

# Check prerequisites
check_prerequisites() {
    log_message "Checking prerequisites..."
    
    if [[ $EUID -eq 0 ]]; then
        log_error "Don't run this script as root! Use your regular user account."
        exit 3
    fi
    
    if [[ ! -f "$PLEX_SQLITE" ]]; then
        log_error "Plex SQLite binary not found at: $PLEX_SQLITE"
        exit 3
    fi
    
    if ! sudo chmod +x "$PLEX_SQLITE" 2>/dev/null; then
        log_warning "Could not make Plex SQLite executable, but will try to use it"
    fi
    
    if [[ ! -f "$MAIN_DB" ]]; then
        log_error "Main database not found at: $MAIN_DB"
        exit 3
    fi
    
    log_success "Prerequisites check passed"
}

# Safe service management with proper synchronization
manage_service() {
    local action="$1"
    local timeout="${2:-30}"
    
    case "$action" in
        "stop")
            log_message "Stopping Plex service..."
            if ! systemctl is-active --quiet "$PLEX_SERVICE"; then
                log_message "Plex service is already stopped"
                return 0
            fi
            
            if sudo systemctl stop "$PLEX_SERVICE"; then
                # Wait for complete shutdown
                local count=0
                while systemctl is-active --quiet "$PLEX_SERVICE" && [[ $count -lt $timeout ]]; do
                    sleep 1
                    ((count++))
                done
                
                if systemctl is-active --quiet "$PLEX_SERVICE"; then
                    log_error "Service failed to stop within ${timeout}s"
                    return 1
                else
                    log_success "Plex service stopped successfully"
                    # Additional wait for complete cleanup
                    sleep 3
                    return 0
                fi
            else
                log_error "Failed to stop Plex service"
                return 1
            fi
            ;;
            
        "start")
            log_message "Starting Plex service..."
            if systemctl is-active --quiet "$PLEX_SERVICE"; then
                log_message "Plex service is already running"
                return 0
            fi
            
            if sudo systemctl start "$PLEX_SERVICE"; then
                # Wait for startup
                local count=0
                while ! systemctl is-active --quiet "$PLEX_SERVICE" && [[ $count -lt $timeout ]]; do
                    sleep 1
                    ((count++))
                done
                
                if systemctl is-active --quiet "$PLEX_SERVICE"; then
                    log_success "Plex service started successfully"
                    return 0
                else
                    log_error "Service failed to start within ${timeout}s"
                    return 1
                fi
            else
                log_error "Failed to start Plex service"
                return 1
            fi
            ;;
    esac
}

# Safe database integrity check (read-only)
check_database_integrity() {
    local db_file="$1"
    local db_name
    db_name=$(basename "$db_file")
    
    log_message "Checking database integrity: $db_name"
    
    # WAL checkpoint if needed (read-only operation)
    local wal_file="${db_file}-wal"
    if [[ -f "$wal_file" ]]; then
        log_message "WAL file detected, performing read-only checkpoint..."
        if sudo "$PLEX_SQLITE" "$db_file" "PRAGMA wal_checkpoint(PASSIVE);" >/dev/null 2>&1; then
            log_success "WAL checkpoint completed"
        else
            log_warning "WAL checkpoint failed, proceeding with integrity check"
        fi
    fi
    
    # Run integrity check
    local integrity_result
    integrity_result=$(sudo "$PLEX_SQLITE" "$db_file" "PRAGMA integrity_check;" 2>&1)
    local check_exit_code=$?
    
    if [[ $check_exit_code -ne 0 ]]; then
        log_error "Failed to run integrity check on $db_name"
        return 1
    fi
    
    if echo "$integrity_result" | grep -q "^ok$"; then
        log_success "Database integrity check passed: $db_name"
        return 0
    else
        log_warning "Database integrity issues detected in $db_name:"
        echo "$integrity_result" | while IFS= read -r line; do
            log_warning "  $line"
        done
        return 1
    fi
}

# Check all databases
check_all_databases() {
    local issues=0
    
    log_message "Starting comprehensive database integrity check..."
    
    for db in "$MAIN_DB" "$BLOBS_DB"; do
        if [[ -f "$db" ]]; then
            if ! check_database_integrity "$db"; then
                ((issues++))
            fi
        else
            log_warning "Database file not found: $(basename "$db")"
            ((issues++))
        fi
    done
    
    if [[ $issues -eq 0 ]]; then
        log_success "All database integrity checks passed"
        return 0
    else
        log_warning "Found integrity issues in $issues database(s)"
        return 1
    fi
}

# Show help
show_help() {
    echo -e "${BOLD}${WHITE}Usage:${RESET} ${CYAN}$(basename "$0")${RESET} ${YELLOW}<command>${RESET} ${DIM}[options]${RESET}"
    echo ""
    echo -e "${BOLD}${WHITE}Commands:${RESET}"
    echo -e "  ${GREEN}${BOLD}check${RESET}              Read-only database integrity check"
    echo -e "  ${YELLOW}${BOLD}repair${RESET}             Interactive database repair"
    echo -e "  ${YELLOW}${BOLD}repair --gentle${RESET}    Gentle repair methods only"
    echo -e "  ${RED}${BOLD}repair --force${RESET}     Aggressive repair methods"
    echo -e "  ${RED}${BOLD}nuclear${RESET}            Nuclear recovery (replace from backup)"
    echo -e "  ${CYAN}${BOLD}help${RESET}               Show this help message"
    echo ""
    echo -e "${BOLD}${WHITE}Examples:${RESET}"
    echo -e "  ${DIM}$(basename "$0") check                    # Safe integrity check${RESET}"
    echo -e "  ${DIM}$(basename "$0") repair                   # Interactive repair${RESET}"
    echo -e "  ${DIM}$(basename "$0") repair --gentle          # Minimal repair only${RESET}"
    echo ""
    echo -e "${BOLD}${YELLOW}⚠️  WARNING:${RESET} Always run ${CYAN}check${RESET} first before attempting repairs!"
    echo ""
}

# Main function
main() {
    if [[ $# -eq 0 ]]; then
        print_header
        show_help
        exit 0
    fi
    
    case "${1,,}" in
        "check")
            print_header
            check_prerequisites
            
            # Stop service for clean check
            if ! manage_service stop; then
                log_error "Cannot perform integrity check while service is running"
                exit 3
            fi
            
            # Check databases
            if check_all_databases; then
                exit_code=0
            else
                exit_code=1
            fi
            
            # Restart service
            if ! manage_service start; then
                log_error "Failed to restart service after check"
                exit 3
            fi
            
            exit $exit_code
            ;;
            
        "repair")
            echo -e "${RED}${BOLD}⚠️  REPAIR FUNCTIONALITY TEMPORARILY DISABLED${RESET}"
            echo -e "${YELLOW}Database repairs are disabled until corruption issues are resolved.${RESET}"
            echo -e "${CYAN}Use the individual repair scripts if manual intervention is needed:${RESET}"
            echo -e "  ${DIM}- plex-database-repair.sh${RESET}"
            echo -e "  ${DIM}- recover-plex-database.sh${RESET}"
            echo -e "  ${DIM}- nuclear-plex-recovery.sh${RESET}"
            exit 2
            ;;
            
        "nuclear")
            echo -e "${RED}${BOLD}⚠️  NUCLEAR RECOVERY TEMPORARILY DISABLED${RESET}"
            echo -e "${YELLOW}Nuclear recovery is disabled until corruption issues are resolved.${RESET}"
            echo -e "${CYAN}Use nuclear-plex-recovery.sh directly if absolutely necessary.${RESET}"
            exit 2
            ;;
            
        "help"|"--help"|"-h")
            print_header
            show_help
            ;;
            
        *)
            print_header
            log_error "Unknown command: $1"
            echo ""
            show_help
            exit 1
            ;;
    esac
}

# Execute main function
main "$@"
