/**
 * PermissionManager.java
 * 
 * Specialized manager for permission handling and notification settings
 * Handles notification permissions, channel management, and exact alarm settings
 * 
 * @author Matthew Raymer
 * @version 2.0.0 - Modular Architecture
 */

package org.timesafari.dailynotification;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.os.PowerManager;

import androidx.core.app.NotificationManagerCompat;

import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;

/**
 * Manager class for permission and settings management
 * 
 * Responsibilities:
 * - Request notification permissions
 * - Check permission status
 * - Manage notification channels
 * - Handle exact alarm settings
 * - Provide comprehensive status checking
 */
public class PermissionManager {
    
    private static final String TAG = "PermissionManager";
    
    private final Context context;
    private final ChannelManager channelManager;
    
    /**
     * Initialize the PermissionManager
     * 
     * @param context Android context
     * @param channelManager Channel manager for notification channels
     */
    public PermissionManager(Context context, ChannelManager channelManager) {
        this.context = context;
        this.channelManager = channelManager;
        
        Log.d(TAG, "PermissionManager initialized");
    }
    
    /**
     * Request notification permissions from the user
     * 
     * @param call Plugin call
     * @param activity Activity for showing permission dialog (required for Android 13+)
     */
    public void requestNotificationPermissions(PluginCall call, android.app.Activity activity) {
        try {
            Log.d(TAG, "Requesting notification permissions");
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                // For Android 13+, request POST_NOTIFICATIONS permission
                if (activity == null) {
                    call.reject("Activity not available - required for permission request");
                    return;
                }
                
                // Check if already granted
                if (androidx.core.content.ContextCompat.checkSelfPermission(context, 
                        android.Manifest.permission.POST_NOTIFICATIONS) 
                        == android.content.pm.PackageManager.PERMISSION_GRANTED) {
                    // Already granted
                    JSObject result = new JSObject();
                    result.put("status", "granted");
                    result.put("granted", true);
                    result.put("notifications", "granted");
                    call.resolve(result);
                } else {
                    // Request permission - activity must handle result via handleRequestPermissionsResult
                    // Note: The plugin should save the call before calling this method
                    androidx.core.app.ActivityCompat.requestPermissions(
                        activity,
                        new String[]{android.Manifest.permission.POST_NOTIFICATIONS},
                         org.timesafari.dailynotification.DailyNotificationConstants.PERMISSION_REQUEST_CODE // Centralized constant
                    );
                    
                    Log.d(TAG, "Permission dialog shown, waiting for user response");
                    // Don't resolve here - wait for handleRequestPermissionsResult in plugin
                }
            } else {
                // For older versions, permissions are granted at install time
                JSObject result = new JSObject();
                result.put("status", "granted");
                result.put("granted", true);
                result.put("notifications", "granted");
                call.resolve(result);
            }
            
        } catch (Exception e) {
            Log.e(TAG, "Error requesting notification permissions", e);
            call.reject("Failed to request permissions: " + e.getMessage());
        }
    }
    
    /**
     * Request notification permissions from the user (backward compatibility - requires activity)
     * 
     * @param call Plugin call
     */
    public void requestNotificationPermissions(PluginCall call) {
        // This version cannot actually request permissions without activity
        // It will only check if already granted
        requestPermission(Manifest.permission.POST_NOTIFICATIONS, call);
    }
    
    /**
     * Get comprehensive permission status
     * Returns PermissionStatus model (single source of truth)
     * 
     * @return PermissionStatus with all permission states
     */
    public org.timesafari.dailynotification.PermissionStatus getPermissionStatus() {
        boolean postNotificationsGranted = false;
        boolean exactAlarmsGranted = false;
        boolean notificationsEnabledAtOsLevel = false;
        boolean batteryOptimizationsIgnored = false;
        
        // Check POST_NOTIFICATIONS permission (Android 13+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            postNotificationsGranted = context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) 
                == PackageManager.PERMISSION_GRANTED;
        } else {
            // Pre-Android 13: check OS-level notification enablement
            postNotificationsGranted = true; // Permission granted at install time
        }
        
        // Always check OS-level notification enablement (important for all API levels)
        notificationsEnabledAtOsLevel = NotificationManagerCompat.from(context).areNotificationsEnabled();
        
        // Check exact alarm permission (Android 12+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            android.app.AlarmManager alarmManager = (android.app.AlarmManager) 
                context.getSystemService(Context.ALARM_SERVICE);
            exactAlarmsGranted = alarmManager != null && alarmManager.canScheduleExactAlarms();
        } else {
            exactAlarmsGranted = true; // Pre-Android 12, exact alarms are always allowed
        }
        
        // Check battery optimizations (Android 6+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                android.os.PowerManager powerManager = (android.os.PowerManager) 
                    context.getSystemService(Context.POWER_SERVICE);
                if (powerManager != null) {
                    batteryOptimizationsIgnored = powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
                }
            } catch (Exception e) {
                Log.w(TAG, "Error checking battery optimizations", e);
                batteryOptimizationsIgnored = false;
            }
        } else {
            batteryOptimizationsIgnored = true; // Pre-Android 6, no battery optimization restrictions
        }
        
        return new org.timesafari.dailynotification.PermissionStatus(
            postNotificationsGranted,
            exactAlarmsGranted,
            batteryOptimizationsIgnored,
            notificationsEnabledAtOsLevel,
            Build.VERSION.SDK_INT
        );
    }
    
    /**
     * Check the current status of notification permissions
     * Delegates to getPermissionStatus() and formats response for JS
     * 
     * @param call Plugin call
     */
    public void checkPermissionStatus(PluginCall call) {
        try {
            Log.d(TAG, "Checking permission status");
            
            org.timesafari.dailynotification.PermissionStatus status = getPermissionStatus();
            
            JSObject result = status.toJSObject();
            result.put("success", true);
            result.put("channelEnabled", channelManager.isChannelEnabled());
            result.put("channelImportance", channelManager.getChannelImportance());
            
            // Add UI-friendly field names for compatibility
            // notificationsEnabled = postNotificationsGranted AND notificationsEnabledAtOsLevel
            boolean postNotificationsGranted = result.getBoolean("postNotificationsGranted", false);
            boolean notificationsEnabledAtOsLevel = result.getBoolean("notificationsEnabledAtOsLevel", false);
            result.put("notificationsEnabled", postNotificationsGranted && notificationsEnabledAtOsLevel);
            // exactAlarmEnabled = exactAlarmGranted
            boolean exactAlarmGranted = result.getBoolean("exactAlarmGranted", false);
            result.put("exactAlarmEnabled", exactAlarmGranted);
            
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking permission status", e);
            call.reject("Failed to check permissions: " + e.getMessage());
        }
    }
    
    /**
     * Check exact alarm permission status
     * Returns detailed information about permission status and whether it can be requested
     * 
     * @param call Plugin call
     */
    public void checkExactAlarmPermission(PluginCall call) {
        try {
            Log.d(TAG, "Checking exact alarm permission");
            
            boolean canSchedule = false;
            boolean canRequest = false;
            boolean required = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
            
            if (required) {
                // Check if exact alarms can be scheduled
                android.app.AlarmManager alarmManager = (android.app.AlarmManager) 
                    context.getSystemService(Context.ALARM_SERVICE);
                canSchedule = alarmManager != null && alarmManager.canScheduleExactAlarms();
                
                // Check if permission can be requested (Android 13+)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    // Try reflection to call Settings.canRequestScheduleExactAlarms()
                    try {
                        java.lang.reflect.Method method = Settings.class.getMethod(
                            "canRequestScheduleExactAlarms",
                            Context.class
                        );
                        canRequest = (Boolean) method.invoke(null, context);
                    } catch (Exception e) {
                        // Fallback heuristic: if exact alarms are not currently allowed,
                        // assume we can request them (safe default)
                        canRequest = !canSchedule;
                    }
                } else {
                    // Android 12 (API 31-32) - permission can always be requested
                    canRequest = true;
                }
            } else {
                // Android 11 and below - permission not needed
                canSchedule = true;
                canRequest = true;
            }
            
            JSObject result = new JSObject();
            result.put("canSchedule", canSchedule);
            result.put("canRequest", canRequest);
            result.put("required", required);
            
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking exact alarm permission", e);
            call.reject("Permission check failed: " + e.getMessage());
        }
    }
    
    /**
     * Request exact alarm permission
     * Opens Settings intent to let user grant the permission
     * 
     * @param call Plugin call
     */
    public void requestExactAlarmPermission(PluginCall call) {
        try {
            Log.d(TAG, "Requesting exact alarm permission");
            
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                // Android 11 and below don't need this permission
                JSObject result = new JSObject();
                result.put("success", true);
                result.put("message", "Exact alarm permission not required on this Android version");
                call.resolve(result);
                return;
            }
            
            // Check if permission is already granted
            android.app.AlarmManager alarmManager = (android.app.AlarmManager) 
                context.getSystemService(Context.ALARM_SERVICE);
            boolean canSchedule = alarmManager != null && alarmManager.canScheduleExactAlarms();
            
            if (canSchedule) {
                // Permission already granted
                JSObject result = new JSObject();
                result.put("success", true);
                result.put("message", "Exact alarm permission already granted");
                call.resolve(result);
                return;
            }
            
            // Check if app can request the permission (Android 13+)
            boolean canRequest = false;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                // Try reflection to call Settings.canRequestScheduleExactAlarms()
                try {
                    java.lang.reflect.Method method = Settings.class.getMethod(
                        "canRequestScheduleExactAlarms",
                        Context.class
                    );
                    canRequest = (Boolean) method.invoke(null, context);
                } catch (Exception e) {
                    // Fallback heuristic: if exact alarms are not currently allowed,
                    // assume we can request them (safe default)
                    canRequest = !canSchedule;
                }
            } else {
                // Android 12 (API 31-32) - permission can always be requested
                canRequest = true;
            }
            
            if (canRequest) {
                // Open Settings to let user grant permission
                try {
                    Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
                    intent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(intent);
                    
                    JSObject result = new JSObject();
                    result.put("success", true);
                    result.put("message", "Please grant 'Alarms & reminders' permission in Settings");
                    call.resolve(result);
                } catch (Exception e) {
                    Log.e(TAG, "Failed to open exact alarm settings", e);
                    call.reject("Failed to open exact alarm settings: " + e.getMessage());
                }
            } else {
                // User has already denied or permission is permanently denied
                // Direct user to app settings
                try {
                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    intent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(intent);
                    
                    call.reject(
                        "Permission denied. Please enable 'Alarms & reminders' in app settings.",
                        "PERMISSION_DENIED"
                    );
                } catch (Exception e) {
                    Log.e(TAG, "Failed to open app settings", e);
                    call.reject("Failed to open app settings: " + e.getMessage());
                }
            }
            
        } catch (Exception e) {
            Log.e(TAG, "Error requesting exact alarm permission", e);
            call.reject("Permission request failed: " + e.getMessage());
        }
    }
    
    /**
     * Open exact alarm settings for the user
     * 
     * @param call Plugin call
     */
    public void openExactAlarmSettings(PluginCall call) {
        try {
            Log.d(TAG, "Opening exact alarm settings");
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
                intent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                
                try {
                    context.startActivity(intent);
                    
                    JSObject result = new JSObject();
                    result.put("success", true);
                    result.put("message", "Exact alarm settings opened");
                    call.resolve(result);
                } catch (Exception e) {
                    Log.e(TAG, "Failed to open exact alarm settings", e);
                    call.reject("Failed to open exact alarm settings: " + e.getMessage());
                }
            } else {
                JSObject result = new JSObject();
                result.put("success", true);
                result.put("message", "Exact alarms not supported on this Android version");
                call.resolve(result);
            }
            
        } catch (Exception e) {
            Log.e(TAG, "Error opening exact alarm settings", e);
            call.reject("Failed to open exact alarm settings: " + e.getMessage());
        }
    }
    
    /**
     * Check if the notification channel is enabled
     * 
     * @param call Plugin call
     */
    public void isChannelEnabled(PluginCall call) {
        try {
            Log.d(TAG, "Checking channel status");
            
            boolean enabled = channelManager.isChannelEnabled();
            int importance = channelManager.getChannelImportance();
            
            JSObject result = new JSObject();
            result.put("success", true);
            result.put("enabled", enabled);
            result.put("importance", importance);
            result.put("channelId", channelManager.getDefaultChannelId());
            
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking channel status", e);
            call.reject("Failed to check channel status: " + e.getMessage());
        }
    }
    
    /**
     * Open notification channel settings for the user
     * 
     * @param call Plugin call
     */
    public void openChannelSettings(PluginCall call) {
        try {
            Log.d(TAG, "Opening channel settings");
            
            boolean opened = channelManager.openChannelSettings();
            
            JSObject result = new JSObject();
            result.put("success", true);
            result.put("opened", opened);
            result.put("message", opened ? "Channel settings opened" : "Failed to open channel settings");
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error opening channel settings", e);
            call.reject("Failed to open channel settings: " + e.getMessage());
        }
    }
    
    /**
     * Get comprehensive status of the notification system
     * 
     * @param call Plugin call
     */
    public void checkStatus(PluginCall call) {
        try {
            Log.d(TAG, "Checking comprehensive status");
            
            // Check permissions
            boolean postNotificationsGranted = false;
            boolean exactAlarmsGranted = false;
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                postNotificationsGranted = context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) 
                    == PackageManager.PERMISSION_GRANTED;
            } else {
                postNotificationsGranted = NotificationManagerCompat.from(context).areNotificationsEnabled();
            }
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                android.app.AlarmManager alarmManager = (android.app.AlarmManager) 
                    context.getSystemService(Context.ALARM_SERVICE);
                exactAlarmsGranted = alarmManager.canScheduleExactAlarms();
            } else {
                exactAlarmsGranted = true;
            }
            
            // Check channel status
            boolean channelEnabled = channelManager.isChannelEnabled();
            int channelImportance = channelManager.getChannelImportance();
            
            // Determine overall status
            boolean canScheduleNow = postNotificationsGranted && channelEnabled && exactAlarmsGranted;
            
            JSObject result = new JSObject();
            result.put("success", true);
            result.put("canScheduleNow", canScheduleNow);
            result.put("postNotificationsGranted", postNotificationsGranted);
            result.put("exactAlarmsGranted", exactAlarmsGranted);
            result.put("channelEnabled", channelEnabled);
            result.put("channelImportance", channelImportance);
            result.put("channelId", channelManager.getDefaultChannelId());
            result.put("androidVersion", Build.VERSION.SDK_INT);
            
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error checking comprehensive status", e);
            call.reject("Failed to check status: " + e.getMessage());
        }
    }
    
    /**
     * Request a specific permission
     * 
     * @param permission Permission to request
     * @param call Plugin call
     */
    private void requestPermission(String permission, PluginCall call) {
        try {
            // This would typically be handled by the Capacitor framework
            // For now, we'll check if the permission is already granted
            boolean granted = context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
            
            JSObject result = new JSObject();
            result.put("success", true);
            result.put("granted", granted);
            result.put("permission", permission);
            result.put("message", granted ? "Permission already granted" : "Permission not granted");
            call.resolve(result);
            
        } catch (Exception e) {
            Log.e(TAG, "Error requesting permission: " + permission, e);
            call.reject("Failed to request permission: " + e.getMessage());
        }
    }
}
