/**
 * DailyNotificationMaintenanceWorker.java
 * 
 * WorkManager worker for maintenance tasks
 * Handles cleanup, optimization, and system health checks
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

import java.util.List;

/**
 * Background worker for maintenance tasks
 * 
 * This worker handles periodic maintenance of the notification system,
 * including cleanup of old data, optimization of storage, and health checks.
 */
public class DailyNotificationMaintenanceWorker extends Worker {
    
    private static final String TAG = "DailyNotificationMaintenanceWorker";
    private static final String KEY_MAINTENANCE_TIME = "maintenance_time";
    
    private static final long WORK_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes total
    private static final int MAX_NOTIFICATIONS_TO_KEEP = 50; // Keep only recent notifications
    
    private final Context context;
    private final DailyNotificationStorage storage;
    
    /**
     * Constructor
     * 
     * @param context Application context
     * @param params Worker parameters
     */
    public DailyNotificationMaintenanceWorker(@NonNull Context context, 
                                            @NonNull WorkerParameters params) {
        super(context, params);
        this.context = context;
        this.storage = new DailyNotificationStorage(context);
    }
    
    /**
     * Main work method - perform maintenance tasks
     * 
     * @return Result indicating success or failure
     */
    @NonNull
    @Override
    public Result doWork() {
        try {
            Log.d(TAG, "Starting maintenance work");
            
            // Get input data
            Data inputData = getInputData();
            long maintenanceTime = inputData.getLong(KEY_MAINTENANCE_TIME, 0);
            
            Log.d(TAG, "Maintenance time: " + maintenanceTime);
            
            // Perform maintenance tasks
            boolean success = performMaintenance();
            
            if (success) {
                Log.i(TAG, "Maintenance completed successfully");
                return Result.success();
            } else {
                Log.w(TAG, "Maintenance completed with warnings");
                return Result.success(); // Still consider it successful
            }
            
        } catch (Exception e) {
            Log.e(TAG, "Error during maintenance work", e);
            return Result.failure();
        }
    }
    
    /**
     * Perform all maintenance tasks
     * 
     * @return true if all tasks completed successfully
     */
    private boolean performMaintenance() {
        try {
            Log.d(TAG, "Performing maintenance tasks");
            
            boolean allSuccessful = true;
            
            // Task 1: Clean up old notifications
            boolean cleanupSuccess = cleanupOldNotifications();
            if (!cleanupSuccess) {
                allSuccessful = false;
            }
            
            // Task 2: Optimize storage
            boolean optimizationSuccess = optimizeStorage();
            if (!optimizationSuccess) {
                allSuccessful = false;
            }
            
            // Task 3: Health check
            boolean healthCheckSuccess = performHealthCheck();
            if (!healthCheckSuccess) {
                allSuccessful = false;
            }
            
            // Task 4: Schedule next maintenance
            scheduleNextMaintenance();
            
            Log.d(TAG, "Maintenance tasks completed. All successful: " + allSuccessful);
            return allSuccessful;
            
        } catch (Exception e) {
            Log.e(TAG, "Error during maintenance tasks", e);
            return false;
        }
    }
    
    /**
     * Clean up old notifications
     * 
     * @return true if cleanup was successful
     */
    private boolean cleanupOldNotifications() {
        try {
            Log.d(TAG, "Cleaning up old notifications");
            
            // Get all notifications
            List<NotificationContent> allNotifications = storage.getAllNotifications();
            int initialCount = allNotifications.size();
            
            if (initialCount <= MAX_NOTIFICATIONS_TO_KEEP) {
                Log.d(TAG, "No cleanup needed, notification count: " + initialCount);
                return true;
            }
            
            // Remove old notifications, keeping the most recent ones
            int notificationsToRemove = initialCount - MAX_NOTIFICATIONS_TO_KEEP;
            int removedCount = 0;
            
            for (int i = 0; i < notificationsToRemove && i < allNotifications.size(); i++) {
                NotificationContent notification = allNotifications.get(i);
                storage.removeNotification(notification.getId());
                removedCount++;
            }
            
            Log.i(TAG, "Cleanup completed. Removed " + removedCount + " old notifications");
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error during notification cleanup", e);
            return false;
        }
    }
    
    /**
     * Optimize storage usage
     * 
     * @return true if optimization was successful
     */
    private boolean optimizeStorage() {
        try {
            Log.d(TAG, "Optimizing storage");
            
            // Get storage statistics
            String stats = storage.getStorageStats();
            Log.d(TAG, "Storage stats before optimization: " + stats);
            
            // Perform storage optimization
            // This could include:
            // - Compacting data structures
            // - Removing duplicate entries
            // - Optimizing cache usage
            
            // For now, just log the current state
            Log.d(TAG, "Storage optimization completed");
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error during storage optimization", e);
            return false;
        }
    }
    
    /**
     * Perform system health check
     * 
     * @return true if health check passed
     */
    private boolean performHealthCheck() {
        try {
            Log.d(TAG, "Performing health check");
            
            boolean healthOk = true;
            
            // Check 1: Storage health
            boolean storageHealth = checkStorageHealth();
            if (!storageHealth) {
                healthOk = false;
            }
            
            // Check 2: Notification count health
            boolean countHealth = checkNotificationCountHealth();
            if (!countHealth) {
                healthOk = false;
            }
            
            // Check 3: Data integrity
            boolean dataIntegrity = checkDataIntegrity();
            if (!dataIntegrity) {
                healthOk = false;
            }
            
            if (healthOk) {
                Log.i(TAG, "Health check passed");
            } else {
                Log.w(TAG, "Health check failed - some issues detected");
            }
            
            return healthOk;
            
        } catch (Exception e) {
            Log.e(TAG, "Error during health check", e);
            return false;
        }
    }
    
    /**
     * Check storage health
     * 
     * @return true if storage is healthy
     */
    private boolean checkStorageHealth() {
        try {
            Log.d(TAG, "Checking storage health");
            
            // Check if storage is accessible
            int notificationCount = storage.getNotificationCount();
            
            if (notificationCount < 0) {
                Log.w(TAG, "Storage health issue: Invalid notification count");
                return false;
            }
            
            // Check if storage is empty (this might be normal)
            if (storage.isEmpty()) {
                Log.d(TAG, "Storage is empty (this might be normal)");
            }
            
            Log.d(TAG, "Storage health check passed");
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking storage health", e);
            return false;
        }
    }
    
    /**
     * Check notification count health
     * 
     * @return true if notification count is healthy
     */
    private boolean checkNotificationCountHealth() {
        try {
            Log.d(TAG, "Checking notification count health");
            
            int notificationCount = storage.getNotificationCount();
            
            // Check for reasonable limits
            if (notificationCount > 1000) {
                Log.w(TAG, "Notification count health issue: Too many notifications (" + 
                    notificationCount + ")");
                return false;
            }
            
            Log.d(TAG, "Notification count health check passed: " + notificationCount);
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking notification count health", e);
            return false;
        }
    }
    
    /**
     * Check data integrity
     * 
     * @return true if data integrity is good
     */
    private boolean checkDataIntegrity() {
        try {
            Log.d(TAG, "Checking data integrity");
            
            // Get all notifications and check basic integrity
            List<NotificationContent> allNotifications = storage.getAllNotifications();
            
            for (NotificationContent notification : allNotifications) {
                // Check required fields
                if (notification.getId() == null || notification.getId().isEmpty()) {
                    Log.w(TAG, "Data integrity issue: Notification with null/empty ID");
                    return false;
                }
                
                if (notification.getTitle() == null || notification.getTitle().isEmpty()) {
                    Log.w(TAG, "Data integrity issue: Notification with null/empty title");
                    return false;
                }
                
                if (notification.getBody() == null || notification.getBody().isEmpty()) {
                    Log.w(TAG, "Data integrity issue: Notification with null/empty body");
                    return false;
                }
                
                // Check timestamp validity
                if (notification.getScheduledTime() <= 0) {
                    Log.w(TAG, "Data integrity issue: Invalid scheduled time");
                    return false;
                }
                
                if (notification.getFetchedAt() <= 0) {
                    Log.w(TAG, "Data integrity issue: Invalid fetch time");
                    return false;
                }
            }
            
            Log.d(TAG, "Data integrity check passed");
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking data integrity", e);
            return false;
        }
    }
    
    /**
     * Schedule next maintenance run
     */
    private void scheduleNextMaintenance() {
        try {
            Log.d(TAG, "Scheduling next maintenance");
            
            // Schedule maintenance for tomorrow at 2 AM
            long nextMaintenanceTime = calculateNextMaintenanceTime();
            
            Data maintenanceData = new Data.Builder()
                .putLong(KEY_MAINTENANCE_TIME, nextMaintenanceTime)
                .build();
            
            androidx.work.OneTimeWorkRequest maintenanceWork = 
                new androidx.work.OneTimeWorkRequest.Builder(DailyNotificationMaintenanceWorker.class)
                    .setInputData(maintenanceData)
                    .setInitialDelay(nextMaintenanceTime - System.currentTimeMillis(), 
                        java.util.concurrent.TimeUnit.MILLISECONDS)
                    .build();
            
            androidx.work.WorkManager.getInstance(context).enqueue(maintenanceWork);
            
            Log.i(TAG, "Next maintenance scheduled for " + nextMaintenanceTime);
            
        } catch (Exception e) {
            Log.e(TAG, "Error scheduling next maintenance", e);
        }
    }
    
    /**
     * Calculate next maintenance time (2 AM tomorrow)
     * 
     * @return Timestamp for next maintenance
     */
    private long calculateNextMaintenanceTime() {
        try {
            java.util.Calendar calendar = java.util.Calendar.getInstance();
            
            // Set to 2 AM
            calendar.set(java.util.Calendar.HOUR_OF_DAY, 2);
            calendar.set(java.util.Calendar.MINUTE, 0);
            calendar.set(java.util.Calendar.SECOND, 0);
            calendar.set(java.util.Calendar.MILLISECOND, 0);
            
            // If 2 AM has passed today, schedule for tomorrow
            if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
                calendar.add(java.util.Calendar.DAY_OF_YEAR, 1);
            }
            
            return calendar.getTimeInMillis();
            
        } catch (Exception e) {
            Log.e(TAG, "Error calculating next maintenance time", e);
            // Fallback: 24 hours from now
            return System.currentTimeMillis() + (24 * 60 * 60 * 1000);
        }
    }
}
