package com.openclaw.alfred.alarm

import android.content.Context
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.net.Uri
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

/**
 * Manages alarm playback with repeating sound and vibration.
 * Singleton pattern so BroadcastReceiver can access the same instance.
 */
class AlarmManager private constructor(private val context: Context) {
    
    companion object {
        @Volatile
        private var instance: AlarmManager? = null
        
        fun getInstance(context: Context): AlarmManager {
            return instance ?: synchronized(this) {
                instance ?: AlarmManager(context.applicationContext).also { instance = it }
            }
        }
    }
    
    private val TAG = "AlarmManager"
    private var mediaPlayer: MediaPlayer? = null
    private var vibrator: Vibrator? = null
    private var vibrateJob: Job? = null
    private val scope = CoroutineScope(Dispatchers.Main)
    
    // Callback for when alarms are dismissed
    var onAlarmDismissed: ((String) -> Unit)? = null
    
    data class ActiveAlarm(
        val id: String,
        val title: String,
        val message: String,
        val timestamp: Long
    )
    
    private val activeAlarms = mutableMapOf<String, ActiveAlarm>()
    
    /**
     * Start an alarm with repeating sound and vibration.
     */
    fun startAlarm(
        alarmId: String,
        title: String,
        message: String,
        enableSound: Boolean = true,
        enableVibrate: Boolean = true
    ) {
        Log.d(TAG, "Starting alarm: $alarmId - $title: $message")
        
        // Store active alarm
        activeAlarms[alarmId] = ActiveAlarm(alarmId, title, message, System.currentTimeMillis())
        
        // Check user preferences
        val prefs = context.getSharedPreferences("alfred_settings", android.content.Context.MODE_PRIVATE)
        val soundEnabled = prefs.getBoolean("alarm_sound_enabled", true)
        val vibrateEnabled = prefs.getBoolean("alarm_vibrate_enabled", true)
        
        // Start sound if enabled in both function param and settings
        if (enableSound && soundEnabled) {
            startAlarmSound()
        }
        
        // Start vibration if enabled in both function param and settings
        if (enableVibrate && vibrateEnabled) {
            startAlarmVibration()
        }
    }
    
    /**
     * Start repeating alarm sound.
     */
    private fun startAlarmSound() {
        try {
            // Stop any existing playback
            stopAlarmSound()
            
            // Get alarm sound URI from preferences, or use default
            val prefs = context.getSharedPreferences("alfred_settings", android.content.Context.MODE_PRIVATE)
            val customUriString = prefs.getString("alarm_sound_uri", null)
            
            val alarmUri = if (customUriString != null) {
                try {
                    Uri.parse(customUriString)
                } catch (e: Exception) {
                    Log.w(TAG, "Failed to parse custom alarm URI, using default", e)
                    RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
                        ?: RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
                }
            } else {
                // Get default alarm sound URI
                RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
                    ?: RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
            }
            
            // Create MediaPlayer
            mediaPlayer = MediaPlayer().apply {
                setDataSource(context, alarmUri)
                
                // Set audio attributes for alarm
                setAudioAttributes(
                    AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_ALARM)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .build()
                )
                
                // Loop the sound
                isLooping = true
                
                // Prepare and start
                prepare()
                start()
            }
            
            Log.d(TAG, "Alarm sound started: $alarmUri")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to start alarm sound", e)
        }
    }
    
    /**
     * Start repeating alarm vibration.
     */
    private fun startAlarmVibration() {
        try {
            vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator
            
            if (vibrator?.hasVibrator() == true) {
                // Vibrate pattern: [delay, vibrate, sleep, vibrate, sleep]
                // 0ms delay, 500ms vibrate, 500ms sleep, repeat
                val pattern = longArrayOf(0, 500, 500)
                
                // Create vibration effect with repeating pattern
                val effect = VibrationEffect.createWaveform(pattern, 0) // 0 = repeat from index 0
                vibrator?.vibrate(effect)
                
                Log.d(TAG, "Alarm vibration started")
            }
        } catch (e: Exception) {
            Log.e(TAG, "Failed to start alarm vibration", e)
        }
    }
    
    /**
     * Stop alarm sound.
     */
    private fun stopAlarmSound() {
        try {
            mediaPlayer?.apply {
                if (isPlaying) {
                    stop()
                }
                release()
            }
            mediaPlayer = null
            Log.d(TAG, "Alarm sound stopped")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to stop alarm sound", e)
        }
    }
    
    /**
     * Stop alarm vibration.
     */
    private fun stopAlarmVibration() {
        try {
            vibrateJob?.cancel()
            vibrateJob = null
            vibrator?.cancel()
            vibrator = null
            Log.d(TAG, "Alarm vibration stopped")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to stop alarm vibration", e)
        }
    }
    
    /**
     * Dismiss a specific alarm.
     */
    fun dismissAlarm(alarmId: String) {
        Log.d(TAG, "Dismissing alarm: $alarmId")
        
        activeAlarms.remove(alarmId)
        
        // Cancel the notification
        com.openclaw.alfred.notifications.NotificationHelper.cancelAlarmNotification(context, alarmId)
        
        // Notify callback (for cross-device sync)
        onAlarmDismissed?.invoke(alarmId)
        
        // If no more active alarms, stop sound and vibration
        if (activeAlarms.isEmpty()) {
            stopAll()
        }
    }
    
    /**
     * Dismiss all active alarms.
     */
    fun dismissAll() {
        Log.d(TAG, "Dismissing all alarms")
        
        // Notify callback for each alarm (for cross-device sync)
        activeAlarms.keys.forEach { alarmId ->
            onAlarmDismissed?.invoke(alarmId)
        }
        
        activeAlarms.clear()
        
        // Cancel ALL alarm notifications (handles any lingering notifications)
        com.openclaw.alfred.notifications.NotificationHelper.cancelAllAlarmNotifications(context)
        
        stopAll()
    }
    
    /**
     * Stop all alarm sounds and vibrations.
     */
    private fun stopAll() {
        stopAlarmSound()
        stopAlarmVibration()
    }
    
    /**
     * Check if there are any active alarms.
     */
    fun hasActiveAlarms(): Boolean = activeAlarms.isNotEmpty()
    
    /**
     * Get all active alarms.
     */
    fun getActiveAlarms(): List<ActiveAlarm> = activeAlarms.values.toList()
    
    /**
     * Cleanup resources.
     */
    fun destroy() {
        dismissAll()
    }
}
