/**
 * DailyNotificationStorageRoom.java
 * 
 * Room-based storage implementation for the DailyNotification plugin
 * Provides enterprise-grade data management with encryption, retention policies, and analytics
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 * @since 2025-10-20
 */

package org.timesafari.dailynotification.storage;

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

import org.timesafari.dailynotification.DailyNotificationDatabase;
import org.timesafari.dailynotification.dao.NotificationContentDao;
import org.timesafari.dailynotification.dao.NotificationDeliveryDao;
import org.timesafari.dailynotification.dao.NotificationConfigDao;
import org.timesafari.dailynotification.entities.NotificationContentEntity;
import org.timesafari.dailynotification.entities.NotificationDeliveryEntity;
import org.timesafari.dailynotification.entities.NotificationConfigEntity;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Room-based storage implementation for the DailyNotification plugin
 * 
 * This class provides:
 * - Enterprise-grade data persistence with Room database
 * - Encryption support for sensitive notification content
 * - Automatic retention policy enforcement
 * - Comprehensive analytics and reporting
 * - Background thread execution for all database operations
 * - Migration support from SharedPreferences-based storage
 */
public class DailyNotificationStorageRoom {
    
    private static final String TAG = "DailyNotificationStorageRoom";
    
    // Database and DAOs (using unified database)
    private DailyNotificationDatabase database;
    private NotificationContentDao contentDao;
    private NotificationDeliveryDao deliveryDao;
    private NotificationConfigDao configDao;
    
    // Thread pool for database operations
    private final ExecutorService executorService;
    
    // Plugin version for migration tracking
    private static final String PLUGIN_VERSION = "1.2.1";
    
    /**
     * Constructor
     * 
     * @param context Application context
     */
    public DailyNotificationStorageRoom(Context context) {
        // Use unified database (Kotlin schema with Java entities)
        this.database = DailyNotificationDatabase.getInstance(context);
        this.contentDao = database.notificationContentDao();
        this.deliveryDao = database.notificationDeliveryDao();
        this.configDao = database.notificationConfigDao();
        this.executorService = Executors.newFixedThreadPool(4);
        
        Log.d(TAG, "Room-based storage initialized with unified database");
    }
    
    // ===== NOTIFICATION CONTENT OPERATIONS =====
    
    /**
     * Save notification content to Room database
     * 
     * @param content Notification content to save
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> saveNotificationContent(NotificationContentEntity content) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                content.pluginVersion = PLUGIN_VERSION;
                content.touch();
                contentDao.insertNotification(content);
                Log.d(TAG, "Saved notification content: " + content.id);
                return true;
            } catch (Exception e) {
                Log.e(TAG, "Failed to save notification content: " + content.id, e);
                return false;
            }
        }, executorService);
    }
    
    /**
     * Get notification content by ID
     * 
     * @param id Notification ID
     * @return CompletableFuture with notification content
     */
    public CompletableFuture<NotificationContentEntity> getNotificationContent(String id) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return contentDao.getNotificationById(id);
            } catch (Exception e) {
                Log.e(TAG, "Failed to get notification content: " + id, e);
                return null;
            }
        }, executorService);
    }
    
    /**
     * Get all notification content for a TimeSafari user
     * 
     * @param timesafariDid TimeSafari DID
     * @return CompletableFuture with list of notifications
     */
    public CompletableFuture<List<NotificationContentEntity>> getNotificationsByTimeSafariDid(String timesafariDid) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return contentDao.getNotificationsByTimeSafariDid(timesafariDid);
            } catch (Exception e) {
                Log.e(TAG, "Failed to get notifications for DID: " + timesafariDid, e);
                return null;
            }
        }, executorService);
    }
    
    /**
     * Get notifications ready for delivery
     * 
     * @return CompletableFuture with list of ready notifications
     */
    public CompletableFuture<List<NotificationContentEntity>> getNotificationsReadyForDelivery() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                long currentTime = System.currentTimeMillis();
                return contentDao.getNotificationsReadyForDelivery(currentTime);
            } catch (Exception e) {
                Log.e(TAG, "Failed to get notifications ready for delivery", e);
                return null;
            }
        }, executorService);
    }
    
    /**
     * Update notification delivery status
     * 
     * @param id Notification ID
     * @param deliveryStatus New delivery status
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> updateNotificationDeliveryStatus(String id, String deliveryStatus) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                NotificationContentEntity content = contentDao.getNotificationById(id);
                if (content != null) {
                    content.deliveryStatus = deliveryStatus;
                    content.touch();
                    contentDao.updateNotification(content);
                    Log.d(TAG, "Updated delivery status for notification: " + id + " to " + deliveryStatus);
                    return true;
                }
                return false;
            } catch (Exception e) {
                Log.e(TAG, "Failed to update delivery status for notification: " + id, e);
                return false;
            }
        }, executorService);
    }
    
    /**
     * Record user interaction with notification
     * 
     * @param id Notification ID
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> recordUserInteraction(String id) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                NotificationContentEntity content = contentDao.getNotificationById(id);
                if (content != null) {
                    content.recordUserInteraction();
                    contentDao.updateNotification(content);
                    Log.d(TAG, "Recorded user interaction for notification: " + id);
                    return true;
                }
                return false;
            } catch (Exception e) {
                Log.e(TAG, "Failed to record user interaction for notification: " + id, e);
                return false;
            }
        }, executorService);
    }
    
    // ===== DELIVERY TRACKING OPERATIONS =====
    
    /**
     * Record notification delivery attempt
     * 
     * @param delivery Delivery tracking entity
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> recordDeliveryAttempt(NotificationDeliveryEntity delivery) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                deliveryDao.insertDelivery(delivery);
                Log.d(TAG, "Recorded delivery attempt: " + delivery.id);
                return true;
            } catch (Exception e) {
                Log.e(TAG, "Failed to record delivery attempt: " + delivery.id, e);
                return false;
            }
        }, executorService);
    }
    
    /**
     * Get delivery history for a notification
     * 
     * @param notificationId Notification ID
     * @return CompletableFuture with delivery history
     */
    public CompletableFuture<List<NotificationDeliveryEntity>> getDeliveryHistory(String notificationId) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return deliveryDao.getDeliveriesByNotificationId(notificationId);
            } catch (Exception e) {
                Log.e(TAG, "Failed to get delivery history for notification: " + notificationId, e);
                return null;
            }
        }, executorService);
    }
    
    /**
     * Get delivery analytics for a TimeSafari user
     * 
     * @param timesafariDid TimeSafari DID
     * @return CompletableFuture with delivery analytics
     */
    public CompletableFuture<DeliveryAnalytics> getDeliveryAnalytics(String timesafariDid) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                List<NotificationDeliveryEntity> deliveries = deliveryDao.getDeliveriesByTimeSafariDid(timesafariDid);
                
                int totalDeliveries = deliveries.size();
                int successfulDeliveries = 0;
                int failedDeliveries = 0;
                long totalDuration = 0;
                int userInteractions = 0;
                
                for (NotificationDeliveryEntity delivery : deliveries) {
                    if (delivery.isSuccessful()) {
                        successfulDeliveries++;
                        totalDuration += delivery.deliveryDurationMs;
                    } else {
                        failedDeliveries++;
                    }
                    
                    if (delivery.hasUserInteraction()) {
                        userInteractions++;
                    }
                }
                
                double successRate = totalDeliveries > 0 ? (double) successfulDeliveries / totalDeliveries : 0.0;
                double averageDuration = successfulDeliveries > 0 ? (double) totalDuration / successfulDeliveries : 0.0;
                double interactionRate = totalDeliveries > 0 ? (double) userInteractions / totalDeliveries : 0.0;
                
                return new DeliveryAnalytics(
                    totalDeliveries,
                    successfulDeliveries,
                    failedDeliveries,
                    successRate,
                    averageDuration,
                    userInteractions,
                    interactionRate
                );
            } catch (Exception e) {
                Log.e(TAG, "Failed to get delivery analytics for DID: " + timesafariDid, e);
                return null;
            }
        }, executorService);
    }
    
    // ===== CONFIGURATION OPERATIONS =====
    
    /**
     * Save configuration value
     * 
     * @param timesafariDid TimeSafari DID (null for global settings)
     * @param configType Configuration type
     * @param configKey Configuration key
     * @param configValue Configuration value
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> saveConfiguration(String timesafariDid, String configType, 
                                                       String configKey, Object configValue) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                String id = timesafariDid != null ? timesafariDid + "_" + configKey : configKey;
                
                NotificationConfigEntity config = new NotificationConfigEntity(
                    id, timesafariDid, configType, configKey, null, null
                );
                config.setTypedValue(configValue);
                config.touch();
                
                configDao.insertConfig(config);
                Log.d(TAG, "Saved configuration: " + configKey + " = " + configValue);
                return true;
            } catch (Exception e) {
                Log.e(TAG, "Failed to save configuration: " + configKey, e);
                return false;
            }
        }, executorService);
    }
    
    /**
     * Get configuration value
     * 
     * @param timesafariDid TimeSafari DID (null for global settings)
     * @param configKey Configuration key
     * @return CompletableFuture with configuration value
     */
    public CompletableFuture<Object> getConfiguration(String timesafariDid, String configKey) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                NotificationConfigEntity config = configDao.getConfigByKeyAndDid(configKey, timesafariDid);
                if (config != null && config.isActive && !config.isExpired()) {
                    return config.getParsedValue();
                }
                return null;
            } catch (Exception e) {
                Log.e(TAG, "Failed to get configuration: " + configKey, e);
                return null;
            }
        }, executorService);
    }
    
    /**
     * Get user preferences
     * 
     * @param timesafariDid TimeSafari DID
     * @return CompletableFuture with user preferences
     */
    public CompletableFuture<List<NotificationConfigEntity>> getUserPreferences(String timesafariDid) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return configDao.getUserPreferences(timesafariDid);
            } catch (Exception e) {
                Log.e(TAG, "Failed to get user preferences for DID: " + timesafariDid, e);
                return null;
            }
        }, executorService);
    }
    
    // ===== CLEANUP OPERATIONS =====
    
    /**
     * Clean up expired data
     * 
     * @return CompletableFuture with cleanup results
     */
    public CompletableFuture<CleanupResults> cleanupExpiredData() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                long currentTime = System.currentTimeMillis();
                
                int deletedNotifications = contentDao.deleteExpiredNotifications(currentTime);
                int deletedDeliveries = deliveryDao.deleteOldDeliveries(currentTime - (30L * 24 * 60 * 60 * 1000));
                int deletedConfigs = configDao.deleteExpiredConfigs(currentTime);
                
                Log.d(TAG, "Cleanup completed: " + deletedNotifications + " notifications, " + 
                          deletedDeliveries + " deliveries, " + deletedConfigs + " configs");
                
                return new CleanupResults(deletedNotifications, deletedDeliveries, deletedConfigs);
            } catch (Exception e) {
                Log.e(TAG, "Failed to cleanup expired data", e);
                return new CleanupResults(0, 0, 0);
            }
        }, executorService);
    }
    
    /**
     * Clear all data for a TimeSafari user
     * 
     * @param timesafariDid TimeSafari DID
     * @return CompletableFuture with success status
     */
    public CompletableFuture<Boolean> clearUserData(String timesafariDid) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                int deletedNotifications = contentDao.deleteNotificationsByTimeSafariDid(timesafariDid);
                int deletedDeliveries = deliveryDao.deleteDeliveriesByTimeSafariDid(timesafariDid);
                int deletedConfigs = configDao.deleteConfigsByTimeSafariDid(timesafariDid);
                
                Log.d(TAG, "Cleared user data for DID: " + timesafariDid + 
                          " (" + deletedNotifications + " notifications, " + 
                          deletedDeliveries + " deliveries, " + deletedConfigs + " configs)");
                return true;
            } catch (Exception e) {
                Log.e(TAG, "Failed to clear user data for DID: " + timesafariDid, e);
                return false;
            }
        }, executorService);
    }
    
    // ===== ANALYTICS OPERATIONS =====
    
    /**
     * Get comprehensive plugin analytics
     * 
     * @return CompletableFuture with plugin analytics
     */
    public CompletableFuture<PluginAnalytics> getPluginAnalytics() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                int totalNotifications = contentDao.getTotalNotificationCount();
                int totalDeliveries = deliveryDao.getTotalDeliveryCount();
                int totalConfigs = configDao.getTotalConfigCount();
                
                int successfulDeliveries = deliveryDao.getSuccessfulDeliveryCount();
                int failedDeliveries = deliveryDao.getFailedDeliveryCount();
                int userInteractions = deliveryDao.getUserInteractionCount();
                
                double successRate = totalDeliveries > 0 ? (double) successfulDeliveries / totalDeliveries : 0.0;
                double interactionRate = totalDeliveries > 0 ? (double) userInteractions / totalDeliveries : 0.0;
                
                return new PluginAnalytics(
                    totalNotifications,
                    totalDeliveries,
                    totalConfigs,
                    successfulDeliveries,
                    failedDeliveries,
                    successRate,
                    userInteractions,
                    interactionRate
                );
            } catch (Exception e) {
                Log.e(TAG, "Failed to get plugin analytics", e);
                return null;
            }
        }, executorService);
    }
    
    // ===== DATA CLASSES =====
    
    /**
     * Delivery analytics data class
     */
    public static class DeliveryAnalytics {
        public final int totalDeliveries;
        public final int successfulDeliveries;
        public final int failedDeliveries;
        public final double successRate;
        public final double averageDuration;
        public final int userInteractions;
        public final double interactionRate;
        
        public DeliveryAnalytics(int totalDeliveries, int successfulDeliveries, int failedDeliveries,
                               double successRate, double averageDuration, int userInteractions, double interactionRate) {
            this.totalDeliveries = totalDeliveries;
            this.successfulDeliveries = successfulDeliveries;
            this.failedDeliveries = failedDeliveries;
            this.successRate = successRate;
            this.averageDuration = averageDuration;
            this.userInteractions = userInteractions;
            this.interactionRate = interactionRate;
        }
        
        @Override
        public String toString() {
            return String.format("DeliveryAnalytics{total=%d, successful=%d, failed=%d, successRate=%.2f%%, avgDuration=%.2fms, interactions=%d, interactionRate=%.2f%%}",
                    totalDeliveries, successfulDeliveries, failedDeliveries, successRate * 100, averageDuration, userInteractions, interactionRate * 100);
        }
    }
    
    /**
     * Cleanup results data class
     */
    public static class CleanupResults {
        public final int deletedNotifications;
        public final int deletedDeliveries;
        public final int deletedConfigs;
        
        public CleanupResults(int deletedNotifications, int deletedDeliveries, int deletedConfigs) {
            this.deletedNotifications = deletedNotifications;
            this.deletedDeliveries = deletedDeliveries;
            this.deletedConfigs = deletedConfigs;
        }
        
        @Override
        public String toString() {
            return String.format("CleanupResults{notifications=%d, deliveries=%d, configs=%d}",
                    deletedNotifications, deletedDeliveries, deletedConfigs);
        }
    }
    
    /**
     * Plugin analytics data class
     */
    public static class PluginAnalytics {
        public final int totalNotifications;
        public final int totalDeliveries;
        public final int totalConfigs;
        public final int successfulDeliveries;
        public final int failedDeliveries;
        public final double successRate;
        public final int userInteractions;
        public final double interactionRate;
        
        public PluginAnalytics(int totalNotifications, int totalDeliveries, int totalConfigs,
                              int successfulDeliveries, int failedDeliveries, double successRate,
                              int userInteractions, double interactionRate) {
            this.totalNotifications = totalNotifications;
            this.totalDeliveries = totalDeliveries;
            this.totalConfigs = totalConfigs;
            this.successfulDeliveries = successfulDeliveries;
            this.failedDeliveries = failedDeliveries;
            this.successRate = successRate;
            this.userInteractions = userInteractions;
            this.interactionRate = interactionRate;
        }
        
        @Override
        public String toString() {
            return String.format("PluginAnalytics{notifications=%d, deliveries=%d, configs=%d, successRate=%.2f%%, interactions=%d, interactionRate=%.2f%%}",
                    totalNotifications, totalDeliveries, totalConfigs, successRate * 100, userInteractions, interactionRate * 100);
        }
    }
    
    /**
     * Close the storage and cleanup resources
     */
    public void close() {
        executorService.shutdown();
        Log.d(TAG, "Room-based storage closed");
    }
}
