#!/bin/bash
set -euo pipefail

# Configuration
SCRIPT_DIR="$HOME/Documents/Photon"
CONFIG_FILE="${SCRIPT_DIR}/photon.conf"
LOCKFILE="${SCRIPT_DIR}/.photon-upload.lock"
LOGFILE="${SCRIPT_DIR}/photon-upload.log"

# When launched as a GUI app there is no TTY — redirect stdout/stderr to the
# log file immediately so nothing tries to write to a closed fd.
mkdir -p "$SCRIPT_DIR"
exec >>"$LOGFILE" 2>&1

# Ensure Homebrew binaries are in PATH when launched as a GUI app
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"

# Debug: Log script invocation
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Script invoked with args: $*" >> /tmp/photon-upload-debug.log
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') PID: $$, PPID: $PPID" >> /tmp/photon-upload-debug.log

# Load configuration (mandatory)
if [[ ! -f "$CONFIG_FILE" ]]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] Config file not found: $CONFIG_FILE" >> "$LOGFILE"
    osascript -e "display alert \"Photon Uploader\" message \"Config file not found:\\n$CONFIG_FILE\" as critical buttons {\"OK\"} default button \"OK\""
    exit 1
fi
source "$CONFIG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] Config loaded: $CONFIG_FILE" >> "$LOGFILE"

# Logging function
log() {
    local level="$1"
    shift
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> "$LOGFILE"
}

# Check dependencies
check_dependencies() {
    local missing_deps=()
    
    log "INFO" "Checking dependencies..."
    
    for cmd in fswatch openssl ssh scp; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            missing_deps+=("$cmd")
        fi
    done
    
    if [[ ${#missing_deps[@]} -gt 0 ]]; then
        log "ERROR" "Missing dependencies: ${missing_deps[*]}"
        log "INFO" "Install with: brew install ${missing_deps[*]}"
        exit 1
    fi
    
    log "INFO" "All dependencies found"
}

# Create necessary directories
setup_directories() {
    log "INFO" "Setting up directories..."
    
    for dir in "$DIR_TO_MONITOR" "$DIR_TO_MOVE" "$DIR_ARCHIVE"; do
        if [[ ! -d "$dir" ]]; then
            log "INFO" "Creating directory: $dir"
            mkdir -p "$dir" || {
                log "ERROR" "Failed to create directory: $dir"
                exit 1
            }
        fi
    done
    
    log "INFO" "Directory setup complete"
}

generate_random_filename() {
    local extension="$1"
    local random_part=$(openssl rand -base64 6 | tr -dc 'A-Za-z' | head -c 8)
    echo "${random_part}.${extension}"
}

# Send system notification
send_notification() {
    if [[ "$ENABLE_NOTIFICATIONS" != "true" ]]; then return; fi
    local NOTIFY_HELPER
    NOTIFY_HELPER="$(dirname "$(dirname "$0")")/Helpers/PhotonNotify.app"
    if [[ -d "$NOTIFY_HELPER" ]]; then
        open -n -jg "$NOTIFY_HELPER" --args "$1" "$2"
    elif command -v osascript >/dev/null; then
        osascript -e "display notification \"$2\" with title \"Photon Uploader\" subtitle \"$1\""
    fi
}

# Check if file extension is supported
is_supported_file() {
    local file="$1"
    local extension="${file##*.}"
    # Convert to lowercase (bash 3.2 compatible)
    extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]')
    [[ ",$SUPPORTED_EXTENSIONS," == *",$extension,"* ]]
}

# Validate SSH key authentication setup
validate_ssh_key() {
    if [[ ! -f "$SSH_KEY_PATH" ]]; then
        log "ERROR" "SSH key not found at: $SSH_KEY_PATH"
        log "INFO" "Generate SSH key with: ssh-keygen -t rsa -b 4096 -f $SSH_KEY_PATH -N ''"
        log "INFO" "Then copy public key to server: ssh-copy-id -i ${SSH_KEY_PATH}.pub -p $PORT $USER@$SERVER"
        return 1
    fi
    
    # Check key permissions
    local key_perms=$(stat -f "%Lp" "$SSH_KEY_PATH" 2>/dev/null || echo "000")
    if [[ "$key_perms" != "600" ]]; then
        log "WARN" "Fixing SSH key permissions: $SSH_KEY_PATH"
        chmod 600 "$SSH_KEY_PATH"
    fi

    return 0
}

# Function to process uploaded files
process_file() {
    local file_path="$1"
    local file_name=$(basename "$file_path")
    
    # Skip hidden files and directories
    if [[ "$file_name" == .* ]] || [[ -d "$file_path" ]]; then
        return 0
    fi
    
    # Check if file exists and is readable
    if [[ ! -f "$file_path" ]] || [[ ! -r "$file_path" ]]; then
        log "WARN" "File not accessible: $file_path"
        return 1
    fi
    
    # Check if file is already being processed
    if is_file_being_processed "$file_path"; then
        log "INFO" "File already being processed: $file_path"
        return 0
    fi
    
    # Check if file type is supported
    if ! is_supported_file "$file_name"; then
        log "INFO" "Unsupported file type: $file_path"
        mark_processing_complete "$file_path"
        return 0
    fi
    
    # Wait for file to be completely written (common with screenshots)
    local file_size=0
    local new_size=1
    while [[ $file_size -ne $new_size ]]; do
        file_size=$new_size
        sleep 0.5
        new_size=$(stat -f%z "$file_path" 2>/dev/null || echo 0)
    done
    
    log "INFO" "Processing file: $file_path"
    
    local extension="${file_name##*.}"
    local new_filename=$(generate_random_filename "$extension")
    local staged_path="$DIR_TO_MOVE/$new_filename"
    
    # Move file to staging area
    if ! cp "$file_path" "$staged_path"; then
        log "ERROR" "Failed to stage file: $file_path"
        mark_processing_complete "$file_path"
        return 1
    fi
    
    # Upload file
    if upload_file "$staged_path" "$new_filename"; then
        mark_processing_complete "$file_path"
        return 0
    else
        mark_processing_complete "$file_path"
        return 1
    fi
}

# Upload file with improved error handling
upload_file() {
    local file_path="$1"
    local filename="$2"
    local url="$BASE_URL/$filename"
    
    log "INFO" "Uploading: $filename"
    
    # Validate SSH key before attempting upload
    if ! validate_ssh_key; then
        log "ERROR" "SSH key validation failed"
        return 1
    fi
    
    # Upload using SSH key authentication
    if scp -P "$PORT" -i "$SSH_KEY_PATH" -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$file_path" "$USER@$SERVER:$REMOTE_DIR"; then
        upload_success=true
    else
        upload_success=false
    fi
    
    if [[ "$upload_success" == "true" ]]; then
        log "INFO" "Upload successful: $filename"
        
        # Copy URL to clipboard
        echo "$url" | pbcopy
        log "INFO" "URL copied to clipboard: $url"
        
        # Send notification
        send_notification "" "$filename uploaded successfully"
        generate_thumbnails
        
        # Archive or cleanup
        if [[ "$CLEANUP_AFTER_UPLOAD" == "true" ]]; then
            if [[ -d "$DIR_ARCHIVE" ]]; then
                mv "$file_path" "$DIR_ARCHIVE/"
                log "INFO" "File archived: $filename"
            else
                rm "$file_path"
                log "INFO" "File removed: $filename"
            fi
        fi
        
        return 0
    else
        log "ERROR" "Upload failed: $filename"
        send_notification "Failed" "Upload failed for $filename"
        return 1
    fi
}

generate_thumbnails() {
    log "INFO" "Requesting thumbnail generation..."
    
    if [[ -z "${PHOTON_DOMAIN:-}" ]]; then
        log "ERROR" "PHOTON_DOMAIN not configured"
        return 1
    fi
    
    local response
    if response=$(curl -s "https://${PHOTON_DOMAIN}/job/generate_thumbnails" 2>&1); then
        
        # Parse JSON response to check status
        if echo "$response" | grep -q '"status":"success"'; then
            log "INFO" "Thumbnail generation completed successfully"
            return 0
        else
            log "WARN" "Thumbnail generation may have failed: $response"
            return 1
        fi
    else
        log "ERROR" "Failed to connect to thumbnail service: $response"
        return 1
    fi
}

# Handle concurrent uploads (bash 3.2 compatible)
ACTIVE_UPLOADS_DIR="${SCRIPT_DIR}/.active_uploads"
PROCESSING_DIR="${SCRIPT_DIR}/.processing"

# Function to check if file is already being processed
is_file_being_processed() {
    local file_path="$1"
    local file_hash=$(echo "$file_path" | shasum -a 256 | cut -d' ' -f1)
    local processing_file="$PROCESSING_DIR/$file_hash"
    
    # Check if processing file exists and is recent (less than 60 seconds old)
    if [[ -f "$processing_file" ]]; then
        local processing_time=$(stat -f%m "$processing_file" 2>/dev/null || echo 0)
        local current_time=$(date +%s)
        if (( current_time - processing_time < 60 )); then
            return 0  # Still being processed
        else
            rm -f "$processing_file" 2>/dev/null || true  # Stale processing file
        fi
    fi
    
    # Create processing marker atomically to prevent race conditions
    mkdir -p "$PROCESSING_DIR"
    if (set -C; echo $$ > "$processing_file") 2>/dev/null; then
        return 1  # Not being processed, marker created
    else
        return 0  # Already being processed by another instance
    fi
}

# Function to mark file processing as complete
mark_processing_complete() {
    local file_path="$1"
    local file_hash=$(echo "$file_path" | shasum -a 256 | cut -d' ' -f1)
    local processing_file="$PROCESSING_DIR/$file_hash"
    rm -f "$processing_file" 2>/dev/null || true
}

# Signal handlers
cleanup() {
    log "INFO" "Shutting down..."
    [[ -f "$LOCKFILE" ]] && rm -f "$LOCKFILE"
    
    # Kill any fswatch processes monitoring our directory
    if command -v pkill >/dev/null 2>&1; then
        pkill -f "fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true
    fi
    
    # Wait for active uploads to complete
    if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
        for upload_file in "$ACTIVE_UPLOADS_DIR"/*; do
            [[ -f "$upload_file" ]] || continue
            local pid=$(basename "$upload_file")
            if kill -0 "$pid" 2>/dev/null; then
                local filename=""
                if [[ -r "$upload_file" ]]; then
                    filename=$(cat "$upload_file" 2>/dev/null || echo "unknown")
                else
                    filename="unknown"
                fi
                log "INFO" "Waiting for upload to complete: $filename"
                wait "$pid" 2>/dev/null || true
            fi
            rm -f "$upload_file" 2>/dev/null || true
        done
        rmdir "$ACTIVE_UPLOADS_DIR" 2>/dev/null || true
    fi
    
    # Clean up processing directory
    if [[ -d "$PROCESSING_DIR" ]]; then
        rm -rf "$PROCESSING_DIR" 2>/dev/null || true
    fi
    
    exit 0
}

# Main function
main() {
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Entering main function" >> /tmp/photon-upload-debug.log
    log "INFO" "Starting screenshot upload service"
    
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Checking for existing lockfile" >> /tmp/photon-upload-debug.log
    # Enhanced lock creation with better race condition protection
    local max_attempts=5
    local attempt=1
    local lock_acquired=false
    
    while [[ $attempt -le $max_attempts ]] && [[ "$lock_acquired" == "false" ]]; do
        echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock attempt $attempt" >> /tmp/photon-upload-debug.log
        
        if (set -C; echo $$ > "$LOCKFILE") 2>/dev/null; then
            lock_acquired=true
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock acquired on attempt $attempt" >> /tmp/photon-upload-debug.log
        else
            existing_pid=$(cat "$LOCKFILE" 2>/dev/null || echo "")
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock exists, checking PID: $existing_pid" >> /tmp/photon-upload-debug.log
            
            if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
                log "ERROR" "Another instance is already running (PID: $existing_pid)"
                echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Existing process $existing_pid is alive, exiting" >> /tmp/photon-upload-debug.log
                exit 1
            else
                echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Stale lock file, removing" >> /tmp/photon-upload-debug.log
                rm -f "$LOCKFILE" 2>/dev/null || true
                sleep 0.1
            fi
        fi
        ((attempt++))
    done
    
    if [[ "$lock_acquired" == "false" ]]; then
        log "ERROR" "Unable to acquire lockfile after $max_attempts attempts"
        exit 1
    fi
    
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Created lockfile with PID: $$" >> /tmp/photon-upload-debug.log
    log "INFO" "Created lockfile with PID: $$"
    
    # Set up signal handlers for this monitoring process only
    trap cleanup SIGINT SIGTERM EXIT
    
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Calling check_dependencies" >> /tmp/photon-upload-debug.log
    # Check dependencies and setup
    check_dependencies
    setup_directories
    
    # Validate SSH key authentication
    log "INFO" "Validating SSH key authentication..."
    if ! validate_ssh_key; then
        log "ERROR" "SSH key authentication setup failed"
        exit 1
    fi
    log "INFO" "SSH key authentication validated successfully"
    
    # Create active uploads tracking directory
    mkdir -p "$ACTIVE_UPLOADS_DIR"
    log "INFO" "Created tracking directory: $ACTIVE_UPLOADS_DIR"
    
    log "INFO" "Monitoring directory: $DIR_TO_MONITOR"
    log "INFO" "Supported file types: $SUPPORTED_EXTENSIONS"
    
    # Test fswatch before starting the main loop
    log "INFO" "Testing fswatch compatibility..."
    if ! fswatch --version >/dev/null 2>&1; then
        log "ERROR" "fswatch not working properly"
        exit 1
    fi
    log "INFO" "fswatch test passed"
    
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') About to start fswatch monitoring" >> /tmp/photon-upload-debug.log
    log "INFO" "Starting file monitoring with fswatch..."
    
    # Create named pipe for fswatch to avoid subshell issues
    local fswatch_pipe="/tmp/fswatch-$$"
    mkfifo "$fswatch_pipe"
    
    # Start fswatch in background writing to pipe
    fswatch -0 "$DIR_TO_MONITOR" > "$fswatch_pipe" &
    local fswatch_pid=$!
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Started fswatch PID: $fswatch_pid" >> /tmp/photon-upload-debug.log
    
    # Cleanup function for pipe
    cleanup_pipe() {
        kill -TERM "$fswatch_pid" 2>/dev/null || true
        rm -f "$fswatch_pipe"
    }
    trap cleanup_pipe EXIT
    
    # Read events from pipe without subshell
    while read -d "" event; do
        echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') fswatch event: $event" >> /tmp/photon-upload-debug.log
        
        # Skip directories and hidden files immediately  
        if [[ -d "$event" ]] || [[ "$(basename "$event")" == .* ]]; then
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Skipping directory/hidden file: $event" >> /tmp/photon-upload-debug.log
            continue
        fi
        
        # Add small delay to allow multiple rapid events to settle
        sleep 0.2
        
        # Limit concurrent uploads
        while true; do
            local active_count=0
            if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
                for upload_file in "$ACTIVE_UPLOADS_DIR"/*; do
                    [[ -f "$upload_file" ]] || continue
                    local pid=$(basename "$upload_file")
                    if kill -0 "$pid" 2>/dev/null; then
                        ((active_count++))
                    else
                        rm -f "$upload_file"
                    fi
                done
            fi
            [[ $active_count -lt $MAX_CONCURRENT_UPLOADS ]] && break
            sleep 0.1
        done
        
        echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Starting background process for: $event" >> /tmp/photon-upload-debug.log
        
        # Process file in background
        (
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background worker PID $$ processing: $event" >> /tmp/photon-upload-debug.log
            process_file "$event"
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background worker PID $$ finished: $event" >> /tmp/photon-upload-debug.log
            rm -f "$ACTIVE_UPLOADS_DIR/$$" 2>/dev/null || true
        ) &
        
        local upload_pid=$!
        echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Spawned upload worker: $upload_pid for $(basename "$event")" >> /tmp/photon-upload-debug.log
        echo "$(basename "$event")" > "$ACTIVE_UPLOADS_DIR/$upload_pid"
    done < "$fswatch_pipe"
}

# Help function
show_help() {
    cat << EOF
Screenshot Upload Service

Usage: $0 [OPTIONS]

Options:
  -h, --help     Show this help message
  -c, --config   Specify config file path
  -d, --daemon   Run in background
  -s, --stop     Stop running daemon
  -t, --test     Test upload with a sample file
  --status       Show service status and related processes
  
Configuration:
  Edit $CONFIG_FILE to customize settings

EOF
}

# Parse command line arguments
BACKGROUND_MODE=false
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -c|--config)
            CONFIG_FILE="$2"
            shift 2
            ;;
        -d|--daemon)
            # Ensure log directory exists
            mkdir -p "$(dirname "$LOGFILE")"
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Starting daemon mode" >> /tmp/photon-upload-debug.log
            # Start daemon with logging
            nohup "$0" --background >> "$LOGFILE" 2>&1 &
            daemon_pid=$!
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Spawned background process: $daemon_pid" >> /tmp/photon-upload-debug.log
            echo "Started in background with PID: $daemon_pid"
            echo "Monitor with: tail -f $LOGFILE"
            exit 0
            ;;
        --background)
            # Internal flag used by daemon mode - don't document in help
            # This prevents infinite daemon loops
            echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background mode activated, breaking from arg parse" >> /tmp/photon-upload-debug.log
            BACKGROUND_MODE=true
            shift
            break
            ;;
        -s|--stop)
            if [[ -f "$LOCKFILE" ]]; then
                pid=$(cat "$LOCKFILE")
                if kill -0 "$pid" 2>/dev/null; then
                    echo "Stopping service with PID: $pid"
                    kill -TERM "$pid"
                    
                    # Also kill any related fswatch processes
                    if command -v pkill >/dev/null 2>&1; then
                        pkill -f "fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true
                        echo "Stopped related fswatch processes"
                    fi
                    
                    # Wait a moment for graceful shutdown
                    sleep 2
                    
                    # Force kill if still running
                    if kill -0 "$pid" 2>/dev/null; then
                        kill -KILL "$pid" 2>/dev/null || true
                        echo "Force killed process $pid"
                    fi
                    
                    echo "Service stopped"
                else
                    echo "Service not running (PID $pid not found)"
                    rm -f "$LOCKFILE"
                fi
            else
                echo "No lockfile found, checking for orphaned processes..."
                
                # Look for orphaned upload or fswatch processes
                if command -v pgrep >/dev/null 2>&1; then
                    orphaned_pids=$(pgrep -f "upload.*background|fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true)
                    if [[ -n "$orphaned_pids" ]]; then
                        echo "Found orphaned processes: $orphaned_pids"
                        kill -TERM $orphaned_pids 2>/dev/null || true
                        sleep 2
                        kill -KILL $orphaned_pids 2>/dev/null || true
                        echo "Cleaned up orphaned processes"
                    else
                        echo "No running processes found"
                    fi
                else
                    echo "Service may not be running"
                fi
            fi
            exit 0
            ;;
        -t|--test)
            echo "Testing upload functionality..."
            check_dependencies
            # Create a test file
            test_file="/tmp/test_$(date +%s).txt"
            echo "Test upload $(date)" > "$test_file"
            process_file "$test_file"
            rm -f "$test_file"
            exit 0
            ;;
        --status)
            echo "Screenshot Upload Service Status"
            echo "================================"
            
            if [[ -f "$LOCKFILE" ]]; then
                lock_pid=$(cat "$LOCKFILE")
                echo "Lock file: $LOCKFILE (PID: $lock_pid)"
                
                if kill -0 "$lock_pid" 2>/dev/null; then
                    echo "Main process: RUNNING (PID: $lock_pid)"
                else
                    echo "Main process: DEAD (stale lock file)"
                fi
            else
                echo "Lock file: NOT FOUND"
            fi
            
            echo ""
            echo "Related processes:"
            if ps aux | grep -E "(upload|fswatch.*$DIR_TO_MONITOR)" | grep -v grep | grep -v status; then
                true
            else
                echo "No related processes found"
            fi
            
            echo ""
            if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
                upload_count=$(ls -1 "$ACTIVE_UPLOADS_DIR" 2>/dev/null | wc -l | tr -d ' ')
                echo "Active uploads: $upload_count"
            else
                echo "Active uploads: 0"
            fi
            
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
done

# Run main function
main
