package org.timesafari.dailynotification;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

/**
 * Manages PendingIntent creation with proper flags and exact alarm handling
 * 
 * Ensures all PendingIntents use correct flags for modern Android versions
 * and provides comprehensive exact alarm permission handling.
 * 
 * @author Matthew Raymer
 * @version 1.0
 */
public class PendingIntentManager {
    private static final String TAG = "PendingIntentManager";
    
    // Modern PendingIntent flags for Android 12+
    private static final int MODERN_PENDING_INTENT_FLAGS = 
        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
    
    // Legacy flags for older Android versions (if needed)
    private static final int LEGACY_PENDING_INTENT_FLAGS = 
        PendingIntent.FLAG_UPDATE_CURRENT;
    
    private final Context context;
    private final AlarmManager alarmManager;
    
    public PendingIntentManager(Context context) {
        this.context = context;
        this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    }
    
    /**
     * Create a PendingIntent for broadcast with proper flags
     * 
     * @param intent The intent to wrap
     * @param requestCode Unique request code
     * @return PendingIntent with correct flags
     */
    public PendingIntent createBroadcastPendingIntent(Intent intent, int requestCode) {
        try {
            int flags = getPendingIntentFlags();
            return PendingIntent.getBroadcast(context, requestCode, intent, flags);
        } catch (Exception e) {
            Log.e(TAG, "Error creating broadcast PendingIntent", e);
            throw e;
        }
    }
    
    /**
     * Create a PendingIntent for activity with proper flags
     * 
     * @param intent The intent to wrap
     * @param requestCode Unique request code
     * @return PendingIntent with correct flags
     */
    public PendingIntent createActivityPendingIntent(Intent intent, int requestCode) {
        try {
            int flags = getPendingIntentFlags();
            return PendingIntent.getActivity(context, requestCode, intent, flags);
        } catch (Exception e) {
            Log.e(TAG, "Error creating activity PendingIntent", e);
            throw e;
        }
    }
    
    /**
     * Create a PendingIntent for service with proper flags
     * 
     * @param intent The intent to wrap
     * @param requestCode Unique request code
     * @return PendingIntent with correct flags
     */
    public PendingIntent createServicePendingIntent(Intent intent, int requestCode) {
        try {
            int flags = getPendingIntentFlags();
            return PendingIntent.getService(context, requestCode, intent, flags);
        } catch (Exception e) {
            Log.e(TAG, "Error creating service PendingIntent", e);
            throw e;
        }
    }
    
    /**
     * Get the appropriate PendingIntent flags for the current Android version
     * 
     * @return Flags to use for PendingIntent creation
     */
    private int getPendingIntentFlags() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return MODERN_PENDING_INTENT_FLAGS;
        } else {
            return LEGACY_PENDING_INTENT_FLAGS;
        }
    }
    
    /**
     * Check if exact alarms can be scheduled
     * 
     * @return true if exact alarms can be scheduled
     */
    public boolean canScheduleExactAlarms() {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                return alarmManager.canScheduleExactAlarms();
            } else {
                return true; // Pre-Android 12, always allowed
            }
        } catch (Exception e) {
            Log.e(TAG, "Error checking exact alarm permission", e);
            return false;
        }
    }
    
    /**
     * Schedule an exact alarm with proper error handling
     * 
     * @param pendingIntent PendingIntent to trigger
     * @param triggerTime When to trigger the alarm
     * @return true if scheduling was successful
     */
    public boolean scheduleExactAlarm(PendingIntent pendingIntent, long triggerTime) {
        try {
            if (!canScheduleExactAlarms()) {
                Log.w(TAG, "Cannot schedule exact alarm - permission not granted");
                return false;
            }
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    triggerTime,
                    pendingIntent
                );
            } else {
                alarmManager.setExact(
                    AlarmManager.RTC_WAKEUP,
                    triggerTime,
                    pendingIntent
                );
            }
            
            Log.d(TAG, "Exact alarm scheduled successfully for " + triggerTime);
            return true;
            
        } catch (SecurityException e) {
            Log.e(TAG, "SecurityException scheduling exact alarm - permission denied", e);
            return false;
        } catch (Exception e) {
            Log.e(TAG, "Error scheduling exact alarm", e);
            return false;
        }
    }
    
    /**
     * Schedule a windowed alarm as fallback
     * 
     * @param pendingIntent PendingIntent to trigger
     * @param triggerTime Target trigger time
     * @param windowLengthMs Window length in milliseconds
     * @return true if scheduling was successful
     */
    public boolean scheduleWindowedAlarm(PendingIntent pendingIntent, long triggerTime, long windowLengthMs) {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alarmManager.setAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    triggerTime,
                    pendingIntent
                );
            } else {
                alarmManager.set(
                    AlarmManager.RTC_WAKEUP,
                    triggerTime,
                    pendingIntent
                );
            }
            
            Log.d(TAG, "Windowed alarm scheduled successfully for " + triggerTime + " (window: " + windowLengthMs + "ms)");
            return true;
            
        } catch (Exception e) {
            Log.e(TAG, "Error scheduling windowed alarm", e);
            return false;
        }
    }
    
    /**
     * Cancel a scheduled alarm
     * 
     * @param pendingIntent PendingIntent to cancel
     * @return true if cancellation was successful
     */
    public boolean cancelAlarm(PendingIntent pendingIntent) {
        try {
            alarmManager.cancel(pendingIntent);
            Log.d(TAG, "Alarm cancelled successfully");
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Error cancelling alarm", e);
            return false;
        }
    }
    
    /**
     * Get detailed alarm scheduling status
     * 
     * @return AlarmStatus object with detailed information
     */
    public AlarmStatus getAlarmStatus() {
        boolean exactAlarmsSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
        boolean exactAlarmsGranted = canScheduleExactAlarms();
        boolean canScheduleNow = exactAlarmsGranted || !exactAlarmsSupported;
        
        return new AlarmStatus(
            exactAlarmsSupported,
            exactAlarmsGranted,
            canScheduleNow,
            Build.VERSION.SDK_INT
        );
    }
    
    /**
     * Data class for alarm status information
     */
    public static class AlarmStatus {
        public final boolean exactAlarmsSupported;
        public final boolean exactAlarmsGranted;
        public final boolean canScheduleNow;
        public final int androidVersion;
        
        public AlarmStatus(boolean exactAlarmsSupported, boolean exactAlarmsGranted, 
                          boolean canScheduleNow, int androidVersion) {
            this.exactAlarmsSupported = exactAlarmsSupported;
            this.exactAlarmsGranted = exactAlarmsGranted;
            this.canScheduleNow = canScheduleNow;
            this.androidVersion = androidVersion;
        }
        
        @Override
        public String toString() {
            return "AlarmStatus{" +
                    "exactAlarmsSupported=" + exactAlarmsSupported +
                    ", exactAlarmsGranted=" + exactAlarmsGranted +
                    ", canScheduleNow=" + canScheduleNow +
                    ", androidVersion=" + androidVersion +
                    '}';
        }
    }
}
