#!/bin/bash

# Phase 1 Testing Script - iOS Interactive Test Runner
# Guides through all Phase 1 tests with clear prompts for UI interaction
# Adapted from Android test-phase1.sh for iOS testing

set -e  # Exit on error

# Source shared library (if exists)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "${SCRIPT_DIR}/ios-test-lib.sh" ]; then
    source "${SCRIPT_DIR}/ios-test-lib.sh"
fi

# Phase 1 specific configuration
APP_BUNDLE_ID="org.timesafari.dailynotification.test"
SIMULATOR_DEVICE="iPhone 15"
LOG_PREFIX="DNP"

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

# Helper functions
print_header() {
    echo ""
    echo -e "${BLUE}========================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo ""
}

print_step() {
    echo -e "${GREEN}[STEP $1]${NC} $2"
    echo ""
}

print_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

print_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

print_warn() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

print_error() {
    echo -e "${RED}❌ $1${NC}"
}

wait_for_user() {
    echo ""
    read -p "Press Enter to continue..."
    echo ""
}

wait_for_ui_action() {
    echo ""
    echo -e "${YELLOW}$1${NC}"
    echo ""
    read -p "Press Enter when done..."
    echo ""
}

# iOS-specific helper functions
get_simulator_id() {
    # First try to find a booted device matching the name
    # Extract UUID from line like: "    iPhone 15 (6514F1D6-80C2-4D0E-8CB4-6F561C8EA1F1) (Booted)"
    local booted_id=$(xcrun simctl list devices | grep "${SIMULATOR_DEVICE}" | grep "Booted" | head -1 | sed -E 's/.*\(([A-F0-9-]{36})\).*\(Booted\).*/\1/')
    if [ -n "${booted_id}" ] && [ "${booted_id}" != "Booted" ]; then
        echo "${booted_id}"
        return 0
    fi
    
    # If no booted device, try available devices
    local available_id=$(xcrun simctl list devices available | grep "${SIMULATOR_DEVICE}" | head -1 | sed -E 's/.*\(([A-F0-9-]{36})\).*/\1/')
    if [ -n "${available_id}" ]; then
        echo "${available_id}"
        return 0
    fi
    
    # Last resort: try any device with similar name (handles "iPhone 15" vs "iPhone 15 Pro")
    # Prefer booted devices
    local any_id=$(xcrun simctl list devices | grep -i "iphone.*15" | grep "Booted" | head -1 | sed -E 's/.*\(([A-F0-9-]{36})\).*\(Booted\).*/\1/')
    if [ -n "${any_id}" ] && [ "${any_id}" != "Booted" ]; then
        echo "${any_id}"
        return 0
    fi
    
    # Try any iPhone 15 device (not necessarily booted)
    any_id=$(xcrun simctl list devices | grep -i "iphone.*15" | head -1 | sed -E 's/.*\(([A-F0-9-]{36})\).*/\1/')
    if [ -n "${any_id}" ]; then
        echo "${any_id}"
        return 0
    fi
    
    return 1
}

get_app_logs() {
    local device_id=$1
    local lines=${2:-50}
    # Use log show (historical) instead of log stream (live) to avoid hanging
    # This matches Android's approach of using logcat -d (historical logs)
    # log stream can block indefinitely waiting for new logs
    # Remove predicate to catch all logs (plugin logs may not match processImagePath predicate)
    xcrun simctl spawn "${device_id}" log show --last 2m --style=compact 2>/dev/null | grep -iE "(dailynotification|ios-test-app|App)" | tail -n "${lines}" || echo ""
}

check_plugin_configured() {
    print_info "Checking if plugin is configured..."
    
    local device_id=$(get_simulator_id)
    if [ -z "${device_id}" ]; then
        print_error "Simulator not found: ${SIMULATOR_DEVICE}"
        return 1
    fi
    
    # Check multiple ways to determine if app is installed/configured:
    # 1. Check if app container exists (most reliable for installed apps)
    local app_container=$(xcrun simctl get_app_container "${device_id}" "${APP_BUNDLE_ID}" 2>/dev/null || echo "")
    
    # 2. Check if app is listed in simulator (installed)
    local app_listed=$(xcrun simctl listapps "${device_id}" 2>/dev/null | grep -c "${APP_BUNDLE_ID}" || echo "0")
    app_listed=$(echo "${app_listed}" | tr -d '\n' | head -1)
    app_listed=${app_listed:-0}
    
    # 3. Check if app data directory exists (indicates app has been launched)
    local data_root="$HOME/Library/Developer/CoreSimulator/Devices/${device_id}/data/Containers/Data/Application"
    local app_data_exists=""
    if [ -d "${data_root}" ]; then
        # Check if any app data directory exists (app has been launched at least once)
        app_data_exists=$(find "${data_root}" -maxdepth 1 -type d 2>/dev/null | head -1 || echo "")
    fi
    
    # If any check indicates app exists, consider it potentially configured
    if [ -n "${app_container}" ] || [ "${app_listed}" -gt "0" ] || [ -n "${app_data_exists}" ]; then
        print_success "App detected (plugin may be configured)"
        print_info "Please verify in the app UI that you see:"
        echo "  ⚙️ Plugin Settings: ✅ Configured"
        echo "  🔌 Native Fetcher: ✅ Configured"
        echo ""
        echo "If both show ✅, the plugin is configured and you can skip configuration."
        echo "If not configured, you'll need to click 'Configure Plugin' in the app UI."
        return 0
    else
        print_info "Plugin not configured (no app data found)"
        print_info "You will need to click 'Configure Plugin' in the app UI"
        return 1
    fi
}

ensure_plugin_configured() {
    if check_plugin_configured; then
        # Plugin might be configured, but let user verify (matches Android pattern)
        wait_for_ui_action "Please check the Plugin Status section at the top of the app.
        
        If you see:
        - ⚙️ Plugin Settings: ✅ Configured
        - 🔌 Native Fetcher: ✅ Configured
        - 🔔 Notifications: ✅ Granted (or similar)
        
        Then the plugin is already configured - just press Enter to continue.
        
        If any show ❌ or 'Not configured':
        - Click 'Request Permissions' if notifications are not granted
        - Click 'Configure Plugin' if settings/fetcher are not configured
        - Wait for all to show ✅, then press Enter."
        
        # Give a moment for any configuration that just happened
        sleep 2
        print_success "Continuing with tests (plugin configuration verified or skipped)"
        return 0
    else
        # Plugin definitely needs configuration
        print_info "Plugin needs configuration"
        
        # First ensure permissions
        ensure_permissions
        
        wait_for_ui_action "Click the 'Configure Plugin' button in the app UI.
        
        Wait for the status to update:
        - ⚙️ Plugin Settings: Should change to ✅ Configured
        - 🔌 Native Fetcher: Should change to ✅ Configured
        
        Once both show ✅, press Enter to continue."
        
        # Verify configuration completed
        sleep 2
        print_success "Plugin configuration completed (or verified)"
    fi
}

check_permissions() {
    print_info "Checking notification permissions..."
    
    # Note: iOS permissions are checked at runtime, not via command line
    # We can only check if the app has been granted permission by checking logs
    print_info "iOS notification permissions are checked at runtime."
    print_info "Please verify in the app UI that notifications are authorized."
    print_info "If not authorized, you'll need to grant permission in the app."
    
    return 0
}

ensure_permissions() {
    if check_permissions; then
        print_success "Permissions check passed"
        return 0
    else
        print_info "Notification permissions needed"
        wait_for_ui_action "In the app UI, click the 'Request Permissions' button.

This will show a system permission dialog.

Steps:
1. Click 'Request Permissions' button
2. In the system dialog, tap 'Allow' to grant notification permission
3. Return to the app and verify the status shows:
   - 🔔 Notifications: ✅ Granted (or similar)

Once permission is granted, press Enter to continue."
        
        return 0
    fi
}

launch_app() {
    print_info "Launching app on simulator..."
    
    local device_id=$(get_simulator_id)
    if [ -z "${device_id}" ]; then
        print_error "Simulator not found: ${SIMULATOR_DEVICE}"
        print_info "Available simulators:"
        xcrun simctl list devices available | grep "iPhone" | head -5
        return 1
    fi
    
    # Boot simulator if not running
    local booted=$(xcrun simctl list devices | grep "${device_id}" | grep -c "Booted" 2>/dev/null || echo "0")
    booted=$(echo "${booted}" | tr -d '\n' | head -1)  # Remove newlines and take first value
    booted=${booted:-0}  # Default to 0 if empty
    if [ "${booted}" -eq "0" ]; then
        print_info "Booting simulator..."
        xcrun simctl boot "${device_id}" 2>/dev/null || true
        sleep 3
    fi
    
    # Launch app
    xcrun simctl launch "${device_id}" "${APP_BUNDLE_ID}" 2>/dev/null || {
        print_warn "App may already be running or needs to be built first"
        print_info "Please build and run the app in Xcode first:"
        echo "  1. Open: test-apps/ios-test-app/ios/App/App.xcworkspace"
        echo "  2. Select simulator: ${SIMULATOR_DEVICE}"
        echo "  3. Press Cmd+R to build and run"
        echo ""
        wait_for_user
    }
    
    sleep 2  # Give app time to launch
    print_success "App launched"
}

get_pending_notifications() {
    local device_id=$(get_simulator_id)
    if [ -z "${device_id}" ]; then
        echo "0"
        return
    fi
    
    # Note: iOS doesn't provide direct command-line access to pending notifications like Android's dumpsys alarm
    # We check logs for the explicit pendingCount that the plugin now logs after scheduling
    # Get logs directly without predicate to catch plugin logs (plugin runs in app process)
    local logs=$(xcrun simctl spawn "${device_id}" log show --last 2m --style=compact 2>/dev/null | grep -iE "(DailyNotificationScheduler|pendingCount|dailynotification)" | tail -100 || echo "")
    
    # Method 1: Look for explicit pendingCount in scheduling logs (most reliable)
    # The plugin logs: "Notification scheduled successfully for ..., id=..., pendingCount=X"
    # Match case-insensitive and extract the number after pendingCount=
    local pending_count=$(echo "${logs}" | grep -iE "pendingCount[=:][[:space:]]*[0-9]+" | tail -1 | grep -oE "[0-9]+" | head -1 || echo "")
    
    # Method 2: Look for "pending" count in status responses
    # The plugin's getNotificationStatus returns "pending": count
    local status_count=$(echo "${logs}" | grep -E "\"pending\"[[:space:]]*:[[:space:]]*[0-9]+" | tail -1 | grep -oE "[0-9]+" | head -1 || echo "")
    
    # Method 3: Count unique notification IDs that were scheduled (fallback)
    # Extract notification IDs from scheduling logs (format: "id=daily_...")
    local notification_ids=$(echo "${logs}" | grep -oE "id=[a-zA-Z0-9_.-]+" | sed 's/id=//' | sort -u | wc -l | tr -d ' ')
    notification_ids=${notification_ids:-0}
    
    # Prefer explicit pendingCount from scheduling log (most reliable)
    if [ -n "${pending_count}" ] && [ "${pending_count}" -ge "0" ] 2>/dev/null && [ "${pending_count}" -le "64" ] 2>/dev/null; then
        echo "${pending_count}"
    # Otherwise use status count if available
    elif [ -n "${status_count}" ] && [ "${status_count}" -ge "0" ] 2>/dev/null && [ "${status_count}" -le "64" ] 2>/dev/null; then
        echo "${status_count}"
    # Fallback to counting unique notification IDs
    elif [ "${notification_ids}" -gt "0" ]; then
        echo "${notification_ids}"
    # Default to 0 if nothing found
    else
        echo "0"
    fi
}

should_run_test() {
    local test_id=$1
    shift
    local selected_tests=("$@")
    
    if [ ${#selected_tests[@]} -eq 0 ]; then
        return 0  # Run all tests if none specified
    fi
    
    for selected in "${selected_tests[@]}"; do
        if [ "${selected}" = "${test_id}" ]; then
            return 0
        fi
    done
    
    return 1
}

# ============================================
# TEST 0: Daily Rollover (Core Contract Verification)
# ============================================
if should_run_test "0" "$@"; then
    print_header "TEST 0: Daily Rollover Verification"
    echo "Purpose: Verify that after a notification fires, the next day's"
    echo "         schedule is correctly computed and only ONE notification exists."
    echo ""
    echo "Note: This test verifies the core 'one notification per day' contract."
    echo "      It requires either:"
    echo "      1. Scheduling a notification for 'now + N seconds' and waiting, OR"
    echo "      2. Manipulating the simulator clock to cross the fire boundary."
    echo ""
    wait_for_user
    
    print_step "1" "Schedule a test notification for near-future..."
    launch_app
    ensure_plugin_configured
    
    INITIAL_COUNT=$(get_pending_notifications)
    print_info "Current pending notifications: ${INITIAL_COUNT}"
    
    wait_for_ui_action "In the app UI, schedule a daily notification.

For this test, you may want to schedule it for a time very soon
(e.g., 1-2 minutes from now) to observe the rollover behavior.

This will schedule:
- 1 notification (UNUserNotificationCenter) for the specified time
- 1 prefetch task (BGTaskScheduler) for 2 minutes before that time"
    
    sleep 3  # Give notification time to be registered
    
    POST_SCHEDULE_COUNT=$(get_pending_notifications)
    print_info "Pending notifications after scheduling: ${POST_SCHEDULE_COUNT}"
    
    print_step "2" "Manual verification steps..."
    echo ""
    echo "To complete this test, you need to:"
    echo "  1. Wait for the notification to fire (or advance simulator clock)"
    echo "  2. Check that the plugin:"
    echo "     - Computed the next day's time (24 hours later)"
    echo "     - Scheduled exactly ONE notification for tomorrow"
    echo "     - Did NOT create duplicate notifications"
    echo "  3. Verify in logs (Xcode Console or Console.app):"
    echo "     - Next run time calculation shows tomorrow's time"
    echo "     - Only one notification scheduled"
    echo ""
    echo "Expected log patterns:"
    echo "  DNP-SCHEDULE: Scheduling next daily notification: ... source=ROLLOVER_ON_FIRE"
    echo "  DNP-NOTIFY: Scheduling notification: triggerTime=<tomorrow's time>"
    echo ""
    
    wait_for_ui_action "After the notification fires (or you advance the clock),
    check the logs and verify:
    
    1. Only ONE notification exists (one per day)
    2. The notification time is for tomorrow (24 hours later)
    3. No duplicate notifications were created
    
    Press Enter when verification is complete."
    
    print_success "TEST 0: Daily Rollover Verification - Manual verification required"
fi

# ============================================
# TEST 1: Cold Start Recovery
# ============================================
if should_run_test "1" "$@"; then
    print_header "TEST 1: Cold Start Recovery"
    echo "Purpose: Verify that when the app launches after termination,"
    echo "         missed notifications are detected and future notifications"
    echo "         are verified/rescheduled."
    echo ""
    wait_for_user
    
    print_step "1" "Schedule a notification for future time..."
    launch_app
    ensure_permissions
    
    wait_for_ui_action "In the app UI, schedule a daily notification for a future time
(e.g., 1 hour from now).

This creates a notification that should persist across app termination."
    
    sleep 2
    
    print_step "2" "Terminate app (simulate cold start)..."
    print_info "Terminating app to simulate cold start scenario..."
    
    device_id=$(get_simulator_id)
    xcrun simctl terminate "${device_id}" "${APP_BUNDLE_ID}" 2>/dev/null || true
    
    print_info "App terminated. Waiting 5 seconds..."
    sleep 5
    
    print_step "3" "Launch app and verify recovery..."
    launch_app
    
    print_info "Checking logs for recovery activity..."
    sleep 3
    
    device_id=$(get_simulator_id)
    logs=$(get_app_logs "${device_id}" 100)
    
    if echo "${logs}" | grep -q "DNP-REACTIVATION\|recovery\|missed"; then
        print_success "Recovery activity detected in logs"
    else
        print_warn "No recovery activity detected in logs"
        print_info "This may indicate recovery is not yet implemented (expected for Phase 1)"
    fi
    
    wait_for_ui_action "Verify in the app UI that:
1. The notification is still scheduled (check 'Scheduled Notifications' screen)
2. Any missed notifications are marked as missed
3. Future notifications are verified/rescheduled

Press Enter when verification is complete."
    
    print_success "TEST 1: Cold Start Recovery - Manual verification required"
fi

# ============================================
# TEST 2: Notification Persistence (Swipe from App Switcher)
# ============================================
if should_run_test "2" "$@"; then
    print_header "TEST 2: Notification Persistence (App Termination)"
    echo "Purpose: Verify that notifications persist when app is terminated"
    echo "         (iOS OS-guaranteed behavior)."
    echo ""
    wait_for_user
    
    print_step "1" "Schedule a notification..."
    launch_app
    ensure_permissions
    
    wait_for_ui_action "In the app UI, schedule a daily notification for a future time."
    
    sleep 2
    
    print_step "2" "Terminate app..."
    print_info "Terminating app (simulating swipe from app switcher)..."
    
    device_id=$(get_simulator_id)
    xcrun simctl terminate "${device_id}" "${APP_BUNDLE_ID}" 2>/dev/null || true
    
    print_info "App terminated. Waiting 3 seconds..."
    sleep 3
    
    print_step "3" "Verify notification still exists..."
    print_info "On iOS, notifications persist automatically (OS-guaranteed)."
    print_info "The notification should still fire even though the app is terminated."
    
    wait_for_ui_action "Verify that:
1. The notification fires at the scheduled time (even though app is terminated)
2. When you tap the notification, the app launches
3. The notification is marked as delivered

Press Enter when verification is complete."
    
    print_success "TEST 2: Notification Persistence - iOS OS-guaranteed behavior verified"
fi

# ============================================
# TEST 3: Invalid Data Handling
# ============================================
if should_run_test "3" "$@"; then
    print_header "TEST 3: Invalid Data Handling"
    echo "Purpose: Verify that the plugin handles invalid data gracefully"
    echo "         without crashing."
    echo ""
    wait_for_user
    
    print_step "1" "Test invalid notification time..."
    launch_app
    ensure_permissions
    
    wait_for_ui_action "In the app UI, try to schedule a notification with invalid data:
1. Empty time string
2. Invalid time format (e.g., '25:00' or '12:99')
3. Negative time values

The app should show an error message and NOT crash."
    
    print_info "Checking logs for error handling..."
    sleep 2
    
    device_id=$(get_simulator_id)
    logs=$(get_app_logs "${device_id}" 50)
    
    # Debug: Show captured logs if verbose (uncomment to debug)
    # echo "DEBUG: Captured logs:"
    # echo "${logs}"
    
    # Check for error patterns (case-insensitive):
    # - error/invalid keywords
    # - DNP-* error prefixes (plugin error logs)
    # - invalid_time_format (error code)
    # - ERROR MESSAGE (Capacitor bridge prefix, if it appears in system logs)
    if echo "${logs}" | grep -qiE "error|invalid|DNP-.*(error|fail|reject)|invalid_time_format|ERROR MESSAGE"; then
        print_success "Error handling detected in logs"
    else
        print_info "No errors in recent system logs (may indicate graceful handling)"
        print_warn "Note: Capacitor bridge errors (⚡️ logs in Xcode console) may not appear in system logs."
        print_info "The plugin uses call.reject() which logs to Xcode console, not system logs."
        print_info "Verify error handling by checking:"
        print_info "  1. Xcode console for ⚡️ ERROR MESSAGE logs"
        print_info "  2. App UI shows error messages (not crashes)"
        print_info "  3. Valid notifications still work after errors"
    fi
    
    wait_for_ui_action "Verify that:
1. Invalid data is rejected with clear error messages
2. The app does NOT crash
3. Valid notifications can still be scheduled after errors

Press Enter when verification is complete."
    
    print_success "TEST 3: Invalid Data Handling - Manual verification required"
fi

# ============================================
# Summary
# ============================================
print_header "Phase 1 Testing Complete"
echo "All Phase 1 tests have been executed."
echo ""
echo "Note: iOS recovery features (ReactivationManager) are NOT yet implemented."
echo "      Tests 1 and 2 will show expected behavior once recovery is implemented."
echo ""
echo "Next Steps:"
echo "  1. Review test results"
echo "  2. Check logs for any errors"
echo "  3. Implement recovery features (Phase 1 directive)"
echo "  4. Re-run tests after implementation"
echo ""

