#!/bin/bash

# Log ANSI Color Code Cleanup Utility
# This script removes ANSI color codes from log files to improve readability
# and reduce file sizes when viewing logs in editors or processing them with tools

set -e

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

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
BACKUP_SUFFIX=".ansi-backup"

# Function to display usage
show_usage() {
    echo -e "${CYAN}Log ANSI Cleanup Utility${NC}"
    echo
    echo "Usage: $0 [OPTIONS] [FILE|DIRECTORY]..."
    echo
    echo "Options:"
    echo "  -h, --help           Show this help message"
    echo "  -r, --recursive      Process directories recursively"
    echo "  -b, --backup         Create backup files before cleaning (recommended)"
    echo "  -n, --no-backup      Don't create backup files (use with caution)"
    echo "  -v, --verbose        Show detailed output"
    echo "  -d, --dry-run        Show what would be done without making changes"
    echo "  -f, --filter PATTERN Only process files matching pattern (e.g., '*.log')"
    echo "  -a, --auto-discover  Find common log files automatically"
    echo
    echo "Examples:"
    echo "  $0 --backup /var/log/app.log"
    echo "  $0 --recursive --backup /var/log/"
    echo "  $0 --auto-discover --backup"
    echo "  $0 --filter '*.log' --recursive /home/user/logs/"
    echo "  $0 --dry-run --auto-discover"
    echo
    echo "Common log locations checked:"
    echo "  - ~/shell/logs/"
    echo "  - ~/shell/crontab/logs/"
    echo "  - ~/shell/plex/logs/"
    echo "  - ~/shell/jellyfin/logs/"
    echo "  - ~/shell/*/logs/ (any subdirectory with logs folder, excluding .git)"
}

# Function to log messages
log_message() {
    local level="$1"
    local message="$2"
    local color=""
    
    case "$level" in
        "INFO")  color="$BLUE" ;;
        "SUCCESS") color="$GREEN" ;;
        "WARNING") color="$YELLOW" ;;
        "ERROR") color="$RED" ;;
        *) color="$NC" ;;
    esac
    
    if [[ "$VERBOSE" == "true" || "$level" != "INFO" ]]; then
        echo -e "${color}${level}: ${message}${NC}"
    fi
}

# Function to check if file contains ANSI codes
has_ansi_codes() {
    local file="$1"
    # Check for both literal \033 and actual escape sequences
    grep -q '\\033\[[0-9;]*m\|\x1b\[[0-9;]*m' "$file" 2>/dev/null
}

# Function to get file size in human readable format
get_file_size() {
    local file="$1"
    if [[ -f "$file" ]]; then
        du -h "$file" | cut -f1
    else
        echo "0B"
    fi
}

# Function to clean ANSI codes from a file
clean_file() {
    local file="$1"
    local backup_file="${file}${BACKUP_SUFFIX}"
    local temp_file
    temp_file=$(mktemp)
    
    if [[ ! -f "$file" ]]; then
        log_message "ERROR" "File not found: $file"
        return 1
    fi
    
    if [[ ! -r "$file" ]]; then
        log_message "ERROR" "Cannot read file: $file"
        return 1
    fi
    
    # Check if file has ANSI codes
    if ! has_ansi_codes "$file"; then
        log_message "INFO" "No ANSI codes found in: $file"
        return 0
    fi
    
    local original_size
    original_size=$(get_file_size "$file")
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_message "INFO" "Would clean ANSI codes from: $file (${original_size})"
        return 0
    fi
    
    # Create backup if requested
    if [[ "$CREATE_BACKUP" == "true" ]]; then
        if ! cp "$file" "$backup_file"; then
            log_message "ERROR" "Failed to create backup: $backup_file"
            return 1
        fi
        log_message "INFO" "Backup created: $backup_file"
    fi
    
    # Clean ANSI codes using multiple patterns to be thorough
    if sed -e 's/\\033\[[0-9;]*m//g' \
           -e 's/\x1b\[[0-9;]*m//g' \
           -e 's/\033\[[0-9;]*m//g' \
           "$file" > "$temp_file"; then
        
        # Verify the temp file was created successfully
        if [[ -s "$temp_file" || ! -s "$file" ]]; then
            if mv "$temp_file" "$file"; then
                local new_size
                new_size=$(get_file_size "$file")
                log_message "SUCCESS" "Cleaned: $file (${original_size} → ${new_size})"
                ((FILES_CLEANED++))
            else
                log_message "ERROR" "Failed to replace original file: $file"
                rm -f "$temp_file"
                return 1
            fi
        else
            log_message "ERROR" "Cleaning resulted in empty file: $file"
            rm -f "$temp_file"
            return 1
        fi
    else
        log_message "ERROR" "Failed to clean ANSI codes from: $file"
        rm -f "$temp_file"
        return 1
    fi
}

# Function to find common log files automatically
auto_discover_logs() {
    local shell_dir="$HOME/shell"
    local search_paths=(
        "$shell_dir/logs"
        "$shell_dir/crontab/logs"
        "$shell_dir/plex/logs"
        "$shell_dir/jellyfin/logs"
    )
    
    # Add any other log directories found in ~/shell (excluding .git/logs)
    while IFS= read -r -d '' dir; do
        # Skip .git/logs and already included directories
        if [[ "$dir" != *"/.git/logs" ]] && 
           [[ "$dir" != "$shell_dir/logs" ]] && 
           [[ "$dir" != "$shell_dir/crontab/logs" ]] && 
           [[ "$dir" != "$shell_dir/plex/logs" ]] && 
           [[ "$dir" != "$shell_dir/jellyfin/logs" ]]; then
            search_paths+=("$dir")
        fi
    done < <(find "$shell_dir" -type d -name "logs" -print0 2>/dev/null)
    
    local found_files=()
    
    for path in "${search_paths[@]}"; do
        if [[ -d "$path" && -r "$path" ]]; then
            # Find log files with common extensions
            while IFS= read -r -d '' file; do
                if [[ -f "$file" && -r "$file" ]]; then
                    found_files+=("$file")
                fi
            done < <(find "$path" -maxdepth 2 \( -name "*.log" -o -name "*.out" -o -name "*.err" \) -type f -print0 2>/dev/null)
        fi
    done
    
    if [[ ${#found_files[@]} -eq 0 ]]; then
        return 1
    fi
    
    for file in "${found_files[@]}"; do
        echo "$file"
    done
}

# Function to process a directory
process_directory() {
    local dir="$1"
    local files_found=0
    
    if [[ ! -d "$dir" ]]; then
        log_message "ERROR" "Directory not found: $dir"
        return 1
    fi
    
    local find_args=("$dir")
    
    if [[ "$RECURSIVE" != "true" ]]; then
        find_args+=("-maxdepth" "1")
    fi
    
    find_args+=("-type" "f")
    
    if [[ -n "$FILE_PATTERN" ]]; then
        find_args+=("-name" "$FILE_PATTERN")
    fi
    
    while IFS= read -r -d '' file; do
        clean_file "$file"
        ((files_found++))
    done < <(find "${find_args[@]}" -print0 2>/dev/null)
    
    if [[ $files_found -eq 0 ]]; then
        log_message "WARNING" "No files found in directory: $dir"
    fi
}

# Initialize variables
RECURSIVE=false
CREATE_BACKUP=true
VERBOSE=false
DRY_RUN=false
FILE_PATTERN=""
AUTO_DISCOVER=false
FILES_CLEANED=0

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -r|--recursive)
            RECURSIVE=true
            shift
            ;;
        -b|--backup)
            CREATE_BACKUP=true
            shift
            ;;
        -n|--no-backup)
            CREATE_BACKUP=false
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -d|--dry-run)
            DRY_RUN=true
            VERBOSE=true
            shift
            ;;
        -f|--filter)
            FILE_PATTERN="$2"
            shift 2
            ;;
        -a|--auto-discover)
            AUTO_DISCOVER=true
            shift
            ;;
        -*)
            echo "Unknown option: $1"
            show_usage
            exit 1
            ;;
        *)
            break
            ;;
    esac
done

# Main execution
log_message "INFO" "Starting ANSI cleanup utility"

if [[ "$DRY_RUN" == "true" ]]; then
    log_message "WARNING" "DRY RUN MODE - No files will be modified"
fi

if [[ "$AUTO_DISCOVER" == "true" ]]; then
    log_message "INFO" "Auto-discovering log files..."
    
    discovered_files=()
    while IFS= read -r file; do
        if [[ -f "$file" ]]; then
            discovered_files+=("$file")
        fi
    done < <(auto_discover_logs)
    
    if [[ ${#discovered_files[@]} -eq 0 ]]; then
        log_message "WARNING" "No log files discovered in common locations"
        log_message "INFO" "Try specifying files or directories manually"
        exit 0
    fi
    
    log_message "INFO" "Found ${#discovered_files[@]} log files"
    for file in "${discovered_files[@]}"; do
        clean_file "$file"
    done
elif [[ $# -eq 0 ]]; then
    log_message "ERROR" "No files or directories specified"
    show_usage
    exit 1
else
    # Process specified files/directories
    for target in "$@"; do
        if [[ -f "$target" ]]; then
            clean_file "$target"
        elif [[ -d "$target" ]]; then
            process_directory "$target"
        else
            log_message "ERROR" "File or directory not found: $target"
        fi
    done
fi

# Summary
if [[ "$DRY_RUN" != "true" ]]; then
    if [[ $FILES_CLEANED -gt 0 ]]; then
        log_message "SUCCESS" "Cleanup completed. $FILES_CLEANED files processed."
        
        if [[ "$CREATE_BACKUP" == "true" ]]; then
            log_message "INFO" "Backup files created with suffix: $BACKUP_SUFFIX"
            log_message "INFO" "Remove backup files when satisfied: rm -f *$BACKUP_SUFFIX"
        fi
    else
        log_message "INFO" "No files needed cleaning."
    fi
else
    log_message "INFO" "Dry run completed. Use without --dry-run to make changes."
fi
