/**
 * DailyNotificationRebootRecoveryManager.java
 * 
 * Android Reboot Recovery Manager for notification restoration
 * Handles system reboots and time changes to restore scheduled notifications
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.util.Log;

import java.util.concurrent.TimeUnit;

/**
 * Manages recovery from system reboots and time changes
 * 
 * This class implements the critical recovery functionality:
 * - Listens for system reboot broadcasts
 * - Handles time change events
 * - Restores scheduled notifications after reboot
 * - Adjusts notification times after time changes
 */
public class DailyNotificationRebootRecoveryManager {
    
    // MARK: - Constants
    
    private static final String TAG = "DailyNotificationRebootRecoveryManager";
    
    // Broadcast actions
    private static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
    private static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
    private static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
    private static final String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
    private static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
    
    // Recovery delay
    private static final long RECOVERY_DELAY_MS = TimeUnit.SECONDS.toMillis(5);
    
    // MARK: - Properties
    
    private final Context context;
    private final DailyNotificationScheduler scheduler;
    private final DailyNotificationExactAlarmManager exactAlarmManager;
    private final DailyNotificationRollingWindow rollingWindow;
    
    // Broadcast receivers
    private BootCompletedReceiver bootCompletedReceiver;
    private TimeChangeReceiver timeChangeReceiver;
    
    // Recovery state
    private boolean recoveryInProgress = false;
    private long lastRecoveryTime = 0;
    
    // MARK: - Initialization
    
    /**
     * Constructor
     * 
     * @param context Application context
     * @param scheduler Notification scheduler
     * @param exactAlarmManager Exact alarm manager
     * @param rollingWindow Rolling window manager
     */
    public DailyNotificationRebootRecoveryManager(Context context, 
                                                 DailyNotificationScheduler scheduler,
                                                 DailyNotificationExactAlarmManager exactAlarmManager,
                                                 DailyNotificationRollingWindow rollingWindow) {
        this.context = context;
        this.scheduler = scheduler;
        this.exactAlarmManager = exactAlarmManager;
        this.rollingWindow = rollingWindow;
        
        Log.d(TAG, "RebootRecoveryManager initialized");
    }
    
    /**
     * Register broadcast receivers
     */
    public void registerReceivers() {
        try {
            Log.d(TAG, "Registering broadcast receivers");
            
            // Register boot completed receiver
            bootCompletedReceiver = new BootCompletedReceiver();
            IntentFilter bootFilter = new IntentFilter();
            bootFilter.addAction(ACTION_BOOT_COMPLETED);
            bootFilter.addAction(ACTION_MY_PACKAGE_REPLACED);
            bootFilter.addAction(ACTION_PACKAGE_REPLACED);
            context.registerReceiver(bootCompletedReceiver, bootFilter);
            
            // Register time change receiver
            timeChangeReceiver = new TimeChangeReceiver();
            IntentFilter timeFilter = new IntentFilter();
            timeFilter.addAction(ACTION_TIME_CHANGED);
            timeFilter.addAction(ACTION_TIMEZONE_CHANGED);
            context.registerReceiver(timeChangeReceiver, timeFilter);
            
            Log.i(TAG, "Broadcast receivers registered successfully");
            
        } catch (Exception e) {
            Log.e(TAG, "Error registering broadcast receivers", e);
        }
    }
    
    /**
     * Unregister broadcast receivers
     */
    public void unregisterReceivers() {
        try {
            Log.d(TAG, "Unregistering broadcast receivers");
            
            if (bootCompletedReceiver != null) {
                context.unregisterReceiver(bootCompletedReceiver);
                bootCompletedReceiver = null;
            }
            
            if (timeChangeReceiver != null) {
                context.unregisterReceiver(timeChangeReceiver);
                timeChangeReceiver = null;
            }
            
            Log.i(TAG, "Broadcast receivers unregistered successfully");
            
        } catch (Exception e) {
            Log.e(TAG, "Error unregistering broadcast receivers", e);
        }
    }
    
    // MARK: - Recovery Methods
    
    /**
     * Handle system reboot recovery
     * 
     * This method restores all scheduled notifications that were lost
     * during the system reboot.
     */
    public void handleSystemReboot() {
        try {
            Log.i(TAG, "Handling system reboot recovery");
            
            // Check if recovery is already in progress
            if (recoveryInProgress) {
                Log.w(TAG, "Recovery already in progress, skipping");
                return;
            }
            
            // Check if recovery was recently performed
            long currentTime = System.currentTimeMillis();
            if (currentTime - lastRecoveryTime < RECOVERY_DELAY_MS) {
                Log.w(TAG, "Recovery performed recently, skipping");
                return;
            }
            
            recoveryInProgress = true;
            lastRecoveryTime = currentTime;
            
            // Perform recovery operations
            performRebootRecovery();
            
            recoveryInProgress = false;
            
            Log.i(TAG, "System reboot recovery completed");
            
        } catch (Exception e) {
            Log.e(TAG, "Error handling system reboot", e);
            recoveryInProgress = false;
        }
    }
    
    /**
     * Handle time change recovery
     * 
     * This method adjusts all scheduled notifications to account
     * for system time changes.
     */
    public void handleTimeChange() {
        try {
            Log.i(TAG, "Handling time change recovery");
            
            // Check if recovery is already in progress
            if (recoveryInProgress) {
                Log.w(TAG, "Recovery already in progress, skipping");
                return;
            }
            
            recoveryInProgress = true;
            
            // Perform time change recovery
            performTimeChangeRecovery();
            
            recoveryInProgress = false;
            
            Log.i(TAG, "Time change recovery completed");
            
        } catch (Exception e) {
            Log.e(TAG, "Error handling time change", e);
            recoveryInProgress = false;
        }
    }
    
    /**
     * Perform reboot recovery operations
     */
    private void performRebootRecovery() {
        try {
            Log.d(TAG, "Performing reboot recovery operations");
            
            // Wait a bit for system to stabilize
            Thread.sleep(2000);
            
            // Restore scheduled notifications
            scheduler.restoreScheduledNotifications();
            
            // Restore rolling window
            rollingWindow.forceMaintenance();
            
            // Log recovery statistics
            logRecoveryStatistics("reboot");
            
        } catch (Exception e) {
            Log.e(TAG, "Error performing reboot recovery", e);
        }
    }
    
    /**
     * Perform time change recovery operations
     */
    private void performTimeChangeRecovery() {
        try {
            Log.d(TAG, "Performing time change recovery operations");
            
            // Adjust scheduled notifications
            scheduler.adjustScheduledNotifications();
            
            // Update rolling window
            rollingWindow.forceMaintenance();
            
            // Log recovery statistics
            logRecoveryStatistics("time_change");
            
        } catch (Exception e) {
            Log.e(TAG, "Error performing time change recovery", e);
        }
    }
    
    /**
     * Log recovery statistics
     * 
     * @param recoveryType Type of recovery performed
     */
    private void logRecoveryStatistics(String recoveryType) {
        try {
            // Get recovery statistics
            int restoredCount = scheduler.getRestoredNotificationCount();
            int adjustedCount = scheduler.getAdjustedNotificationCount();
            
            Log.i(TAG, String.format("Recovery statistics (%s): restored=%d, adjusted=%d", 
                recoveryType, restoredCount, adjustedCount));
            
        } catch (Exception e) {
            Log.e(TAG, "Error logging recovery statistics", e);
        }
    }
    
    // MARK: - Broadcast Receivers
    
    /**
     * Broadcast receiver for boot completed events
     */
    private class BootCompletedReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                String action = intent.getAction();
                Log.d(TAG, "BootCompletedReceiver received action: " + action);
                
                if (ACTION_BOOT_COMPLETED.equals(action) || 
                    ACTION_MY_PACKAGE_REPLACED.equals(action) || 
                    ACTION_PACKAGE_REPLACED.equals(action)) {
                    
                    // Handle system reboot
                    handleSystemReboot();
                }
                
            } catch (Exception e) {
                Log.e(TAG, "Error in BootCompletedReceiver", e);
            }
        }
    }
    
    /**
     * Broadcast receiver for time change events
     */
    private class TimeChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                String action = intent.getAction();
                Log.d(TAG, "TimeChangeReceiver received action: " + action);
                
                if (ACTION_TIME_CHANGED.equals(action) || 
                    ACTION_TIMEZONE_CHANGED.equals(action)) {
                    
                    // Handle time change
                    handleTimeChange();
                }
                
            } catch (Exception e) {
                Log.e(TAG, "Error in TimeChangeReceiver", e);
            }
        }
    }
    
    // MARK: - Public Methods
    
    /**
     * Get recovery status
     * 
     * @return Recovery status information
     */
    public RecoveryStatus getRecoveryStatus() {
        return new RecoveryStatus(
            recoveryInProgress,
            lastRecoveryTime,
            System.currentTimeMillis() - lastRecoveryTime
        );
    }
    
    /**
     * Force recovery (for testing)
     */
    public void forceRecovery() {
        Log.i(TAG, "Forcing recovery");
        handleSystemReboot();
    }
    
    /**
     * Check if recovery is needed
     * 
     * @return true if recovery is needed
     */
    public boolean isRecoveryNeeded() {
        // Check if system was recently rebooted
        long currentTime = System.currentTimeMillis();
        long timeSinceLastRecovery = currentTime - lastRecoveryTime;
        
        // Recovery needed if more than 1 hour since last recovery
        return timeSinceLastRecovery > TimeUnit.HOURS.toMillis(1);
    }
    
    // MARK: - Status Classes
    
    /**
     * Recovery status information
     */
    public static class RecoveryStatus {
        public final boolean inProgress;
        public final long lastRecoveryTime;
        public final long timeSinceLastRecovery;
        
        public RecoveryStatus(boolean inProgress, long lastRecoveryTime, long timeSinceLastRecovery) {
            this.inProgress = inProgress;
            this.lastRecoveryTime = lastRecoveryTime;
            this.timeSinceLastRecovery = timeSinceLastRecovery;
        }
        
        @Override
        public String toString() {
            return String.format("RecoveryStatus{inProgress=%s, lastRecovery=%d, timeSince=%d}", 
                inProgress, lastRecoveryTime, timeSinceLastRecovery);
        }
    }
}
