/**
 * DailyNotificationReceiver.java
 * 
 * Broadcast receiver for handling scheduled notification alarms
 * Displays notifications when scheduled time is reached
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Trace;
import android.util.Log;

import androidx.core.app.NotificationCompat;
import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

/**
 * Broadcast receiver for daily notification alarms
 * 
 * This receiver is triggered by AlarmManager when it's time to display
 * a notification. It retrieves the notification content from storage
 * and displays it to the user.
 */
public class DailyNotificationReceiver extends BroadcastReceiver {
    
    private static final String TAG = "DailyNotificationReceiver";
    private static final String CHANNEL_ID = "timesafari.daily";
    private static final String EXTRA_NOTIFICATION_ID = "notification_id";
    
    /**
     * Handle broadcast intent when alarm triggers
     * 
     * Ultra-lightweight receiver that only parses intent and enqueues work.
     * All heavy operations (storage, JSON, scheduling) are moved to WorkManager.
     * 
     * @param context Application context
     * @param intent Broadcast intent
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        Trace.beginSection("DN:onReceive");
        try {
            Log.d(TAG, "DN|RECEIVE_START action=" + intent.getAction());
            
            String action = intent.getAction();
            if (action == null) {
                Log.w(TAG, "DN|RECEIVE_ERR null_action");
                return;
            }
            
            if ("org.timesafari.daily.NOTIFICATION".equals(action)) {
                // Parse intent and enqueue work - keep receiver ultra-light
                String notificationId = intent.getStringExtra(EXTRA_NOTIFICATION_ID);
                if (notificationId == null) {
                    Log.w(TAG, "DN|RECEIVE_ERR missing_id");
                    return;
                }
                
                // Enqueue work immediately - don't block receiver
                // Pass the full intent to extract static reminder extras
                enqueueNotificationWork(context, notificationId, intent);
                Log.d(TAG, "DN|RECEIVE_OK enqueued=" + notificationId);
                
            } else if ("org.timesafari.daily.DISMISS".equals(action)) {
                // Handle dismissal - also lightweight
                String notificationId = intent.getStringExtra(EXTRA_NOTIFICATION_ID);
                if (notificationId != null) {
                    enqueueDismissalWork(context, notificationId);
                    Log.d(TAG, "DN|DISMISS_OK enqueued=" + notificationId);
                }
            } else {
                Log.w(TAG, "DN|RECEIVE_ERR unknown_action=" + action);
            }
            
        } catch (Exception e) {
            Log.e(TAG, "DN|RECEIVE_ERR exception=" + e.getMessage(), e);
        } finally {
            Trace.endSection();
        }
    }
    
    /**
     * Enqueue notification processing work to WorkManager with deduplication
     * 
     * Uses unique work name based on notification ID to prevent duplicate
     * work items from being enqueued for the same notification. WorkManager's
     * enqueueUniqueWork automatically prevents duplicates when using the same
     * work name.
     * 
     * @param context Application context
     * @param notificationId ID of notification to process
     * @param intent Intent containing notification data (may include static reminder extras)
     */
    private void enqueueNotificationWork(Context context, String notificationId, Intent intent) {
        try {
            // Create unique work name based on notification ID to prevent duplicates
            // WorkManager will automatically skip if work with this name already exists
            String workName = "display_" + notificationId;

            // Extract static reminder extras from intent if present
            // Static reminders have title/body in Intent extras, not in storage.
            // Do NOT access DB on main thread here (Room disallows it); Worker will resolve
            // missing title/body by schedule_id on a background thread (see plugin-feedback-android-rollover-double-fire).
            boolean isStaticReminder = intent.getBooleanExtra("is_static_reminder", false);
            String title = intent.getStringExtra("title");
            String body = intent.getStringExtra("body");
            boolean sound = intent.getBooleanExtra("sound", true);
            boolean vibration = intent.getBooleanExtra("vibration", true);
            String priority = intent.getStringExtra("priority");
            if (priority == null) {
                priority = "normal";
            }
            String scheduleId = intent.getStringExtra("schedule_id");

            Data.Builder dataBuilder = new Data.Builder()
                .putString("notification_id", notificationId)
                .putString("action", "display")
                .putBoolean("is_static_reminder", isStaticReminder);
            if (scheduleId != null && !scheduleId.isEmpty()) {
                dataBuilder.putString("schedule_id", scheduleId);
            }

            // Add static reminder data when present (from Intent; Worker resolves from DB by schedule_id if missing)
            if (isStaticReminder && title != null && body != null) {
                dataBuilder.putString("title", title)
                    .putString("body", body)
                    .putBoolean("sound", sound)
                    .putBoolean("vibration", vibration)
                    .putString("priority", priority);
                Log.d(TAG, "DN|WORK_ENQUEUE static_reminder id=" + notificationId);
            }

            Data inputData = dataBuilder.build();
            
            OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(DailyNotificationWorker.class)
                .setInputData(inputData)
                .addTag("daily_notification_display")
                .build();
            
            // Use unique work name with KEEP policy (don't replace if exists)
            // This prevents duplicate work items from being enqueued even if
            // the receiver is triggered multiple times for the same notification
            WorkManager.getInstance(context).enqueueUniqueWork(
                workName,
                ExistingWorkPolicy.KEEP,
                workRequest
            );
            
            Log.d(TAG, "DN|WORK_ENQUEUE display=" + notificationId + " work_name=" + workName);
            
        } catch (Exception e) {
            Log.e(TAG, "DN|WORK_ENQUEUE_ERR display=" + notificationId + " err=" + e.getMessage(), e);
        }
    }
    
    /**
     * Enqueue notification dismissal work to WorkManager with deduplication
     * 
     * Uses unique work name based on notification ID to prevent duplicate
     * dismissal work items.
     * 
     * @param context Application context
     * @param notificationId ID of notification to dismiss
     */
    private void enqueueDismissalWork(Context context, String notificationId) {
        try {
            // Create unique work name based on notification ID to prevent duplicates
            String workName = "dismiss_" + notificationId;
            
            Data inputData = new Data.Builder()
                .putString("notification_id", notificationId)
                .putString("action", "dismiss")
                .build();
            
            OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(DailyNotificationWorker.class)
                .setInputData(inputData)
                .addTag("daily_notification_dismiss")
                .build();
            
            // Use unique work name with REPLACE policy (allow new dismissal to replace pending)
            WorkManager.getInstance(context).enqueueUniqueWork(
                workName,
                ExistingWorkPolicy.REPLACE,
                workRequest
            );
            
            Log.d(TAG, "DN|WORK_ENQUEUE dismiss=" + notificationId + " work_name=" + workName);
            
        } catch (Exception e) {
            Log.e(TAG, "DN|WORK_ENQUEUE_ERR dismiss=" + notificationId + " err=" + e.getMessage(), e);
        }
    }

    // handleNotificationIntent/performJITFreshnessCheck/displayNotification/
    // scheduleNextNotification/convertTimeToCron/calculateNextRunTimeFromCron/
    // getNotificationPriority were removed here (PLAN-simplify-static-and-refactor.md §3.6):
    // onReceive() only ever calls enqueueNotificationWork()/enqueueDismissalWork() above, so
    // this entire chain — including scheduleNextNotification's "daily_rollover_<timestamp>"
    // orphan-id fallback (generator #4, the other source of stray uncancellable schedules) —
    // was confirmed dead (zero callers) and fully superseded by DailyNotificationWorker.java's
    // live equivalents.
    
    /**
     * Handle notification dismissal
     * 
     * @param context Application context
     * @param notificationId ID of dismissed notification
     */
    private void handleNotificationDismissal(Context context, String notificationId) {
        try {
            Log.d(TAG, "Handling notification dismissal: " + notificationId);
            
            // Remove from storage
            DailyNotificationStorage storage = new DailyNotificationStorage(context);
            storage.removeNotification(notificationId);
            
            // Cancel any pending alarms
            DailyNotificationScheduler scheduler = new DailyNotificationScheduler(
                context,
                (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE)
            );
            scheduler.cancelNotification(notificationId);
            
            Log.i(TAG, "Notification dismissed successfully: " + notificationId);
            
        } catch (Exception e) {
            Log.e(TAG, "Error handling notification dismissal", e);
        }
    }
}
