package com.bitchat.android.mesh

import android.bluetooth.le.AdvertiseSettings
import android.bluetooth.le.ScanSettings
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import kotlinx.coroutines.*
import kotlin.math.max

/**
 * Power-aware Bluetooth management for bitchat
 * Adjusts scanning, advertising, and connection behavior based on battery state
 */
class PowerManager(private val context: Context) : LifecycleEventObserver {
    
    companion object {
        private const val TAG = "PowerManager"
        
        // Battery thresholds
        private const val CRITICAL_BATTERY = com.bitchat.android.util.AppConstants.Power.CRITICAL_BATTERY_PERCENT
        private const val LOW_BATTERY = com.bitchat.android.util.AppConstants.Power.LOW_BATTERY_PERCENT
        private const val MEDIUM_BATTERY = com.bitchat.android.util.AppConstants.Power.MEDIUM_BATTERY_PERCENT
        
        // Scan duty cycle periods (ms)
        private const val SCAN_ON_DURATION_NORMAL = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_NORMAL_MS    // 8 seconds on
        private const val SCAN_OFF_DURATION_NORMAL = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_NORMAL_MS   // 2 seconds off
        private const val SCAN_ON_DURATION_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_POWER_SAVE_MS    // 2 seconds on
        private const val SCAN_OFF_DURATION_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_POWER_SAVE_MS  // 8 seconds off
        private const val SCAN_ON_DURATION_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_ULTRA_LOW_MS      // 1 second on
        private const val SCAN_OFF_DURATION_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_ULTRA_LOW_MS   // 10 seconds off
        
        // Connection limits
        private const val MAX_CONNECTIONS_NORMAL = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_NORMAL
        private const val MAX_CONNECTIONS_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_POWER_SAVE
        private const val MAX_CONNECTIONS_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_ULTRA_LOW
    }
    
    enum class PowerMode {
        PERFORMANCE,    // Full power, no restrictions
        BALANCED,       // Moderate power saving
        POWER_SAVER,    // Aggressive power saving
        ULTRA_LOW_POWER // Minimal operations only
    }
    
    private var currentMode = PowerMode.BALANCED
    private var isCharging = false
    private var batteryLevel = 100
    private var isAppInBackground = true
    
    private val powerScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private var dutyCycleJob: Job? = null
    
    var delegate: PowerManagerDelegate? = null
    
    // Battery monitoring
    private val batteryReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                Intent.ACTION_BATTERY_CHANGED -> {
                    val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
                    val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
                    if (level != -1 && scale != -1) {
                        batteryLevel = (level * 100) / scale
                    }
                    
                    val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
                    isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                                status == BatteryManager.BATTERY_STATUS_FULL
                    
                    updatePowerMode()
                }
                Intent.ACTION_POWER_CONNECTED -> {
                    isCharging = true
                    updatePowerMode()
                }
                Intent.ACTION_POWER_DISCONNECTED -> {
                    isCharging = false
                    updatePowerMode()
                }
            }
        }
    }
    
    init {
        registerBatteryReceiver()
        
        // Register for process lifecycle events on the main thread
        Handler(Looper.getMainLooper()).post {
            try {
                ProcessLifecycleOwner.get().lifecycle.addObserver(this)
            } catch (e: Exception) {
                Log.e(TAG, "Failed to register lifecycle observer: ${e.message}")
            }
        }
        
        updatePowerMode()
    }
    
    fun start() {
        Log.i(TAG, "Starting power management")
        startDutyCycle()
    }
    
    fun stop() {
        Log.i(TAG, "Stopping power management")
        powerScope.cancel()
        unregisterBatteryReceiver()
        
        // Unregister lifecycle observer
        Handler(Looper.getMainLooper()).post {
            try {
                ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
            } catch (e: Exception) {
                 Log.e(TAG, "Failed to remove lifecycle observer: ${e.message}")
            }
        }
    }
    
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        when (event) {
            Lifecycle.Event.ON_START -> {
                Log.d(TAG, "Process lifecycle: ON_START (App coming to foreground)")
                isAppInBackground = false
                updatePowerMode()
            }
            Lifecycle.Event.ON_STOP -> {
                Log.d(TAG, "Process lifecycle: ON_STOP (App going to background)")
                isAppInBackground = true
                updatePowerMode()
            }
            else -> {}
        }
    }
    
    /**
     * Get scan settings optimized for current power mode
     */
    fun getScanSettings(): ScanSettings {
        val builder = ScanSettings.Builder()
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)

        when (currentMode) {
            PowerMode.PERFORMANCE -> builder
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
                .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)

            PowerMode.BALANCED -> builder
                .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
                .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
                .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)

            PowerMode.POWER_SAVER -> builder
                .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
                .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)

            PowerMode.ULTRA_LOW_POWER -> builder
                .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
                .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
        }

        return builder.setReportDelay(0).build()
    }
    
    /**
     * Get advertising settings optimized for current power mode
     */
    fun getAdvertiseSettings(): AdvertiseSettings {
        return when (currentMode) {
            PowerMode.PERFORMANCE -> AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
                .setConnectable(true)
                .setTimeout(0)
                .build()
                
            PowerMode.BALANCED -> AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
                .setConnectable(true)
                .setTimeout(0)
                .build()
                
            PowerMode.POWER_SAVER -> AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)
                .setConnectable(true)
                .setTimeout(0)
                .build()
                
            PowerMode.ULTRA_LOW_POWER -> AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW)
                .setConnectable(true)
                .setTimeout(0)
                .build()
        }
    }
    
    /**
     * Get maximum allowed connections for current power mode
     */
    fun getMaxConnections(): Int {
        return when (currentMode) {
            PowerMode.PERFORMANCE -> MAX_CONNECTIONS_NORMAL
            PowerMode.BALANCED -> MAX_CONNECTIONS_NORMAL
            PowerMode.POWER_SAVER -> MAX_CONNECTIONS_POWER_SAVE
            PowerMode.ULTRA_LOW_POWER -> MAX_CONNECTIONS_ULTRA_LOW
        }
    }
    
    /**
     * Get RSSI filter threshold for current power mode
     */
    fun getRSSIThreshold(): Int {
        return when (currentMode) {
            PowerMode.PERFORMANCE -> -95
            PowerMode.BALANCED -> -85
            PowerMode.POWER_SAVER -> -75
            PowerMode.ULTRA_LOW_POWER -> -65
        }
    }
    
    /**
     * Check if duty cycling should be used
     */
    fun shouldUseDutyCycle(): Boolean {
        return currentMode != PowerMode.PERFORMANCE
    }
    
    /**
     * Get current power mode information
     */
    fun getPowerInfo(): String {
        return buildString {
            appendLine("=== Power Manager Status ===")
            appendLine("Current Mode: $currentMode")
            appendLine("Battery Level: $batteryLevel%")
            appendLine("Is Charging: $isCharging")
            appendLine("App In Background: $isAppInBackground")
            appendLine("Max Connections: ${getMaxConnections()}")
            appendLine("RSSI Threshold: ${getRSSIThreshold()} dBm")
            appendLine("Use Duty Cycle: ${shouldUseDutyCycle()}")
        }
    }
    
    private fun updatePowerMode() {
        // Determine the base mode from battery/charging state only
        val baseMode = when {
            // Charging in foreground may use performance
            isCharging && !isAppInBackground -> PowerMode.PERFORMANCE

            // Critical battery - force ultra low power regardless of foreground/background
            batteryLevel <= CRITICAL_BATTERY -> PowerMode.ULTRA_LOW_POWER

            // Low battery - prefer power saver
            batteryLevel <= LOW_BATTERY -> PowerMode.POWER_SAVER

            // Otherwise balanced
            else -> PowerMode.BALANCED
        }

        // If app is in background (including when running as a foreground service),
        // cap the power mode to at least POWER_SAVER. Preserve ULTRA_LOW_POWER.
        val newMode = if (isAppInBackground) {
            if (baseMode == PowerMode.ULTRA_LOW_POWER) PowerMode.ULTRA_LOW_POWER else PowerMode.POWER_SAVER
        } else {
            baseMode
        }

        if (newMode != currentMode) {
            val oldMode = currentMode
            currentMode = newMode
            Log.i(TAG, "Power mode changed: $oldMode → $newMode (battery: $batteryLevel%, charging: $isCharging, background: $isAppInBackground)")
            
            delegate?.onPowerModeChanged(currentMode)
            
            // Restart duty cycle with new parameters
            if (shouldUseDutyCycle()) {
                startDutyCycle()
            } else {
                stopDutyCycle()
            }
        }
    }
    
    private fun startDutyCycle() {
        stopDutyCycle()
        
        if (!shouldUseDutyCycle()) {
            delegate?.onScanStateChanged(true) // Always scan in performance mode
            return
        }
        
        val (onDuration, offDuration) = when (currentMode) {
            PowerMode.BALANCED -> SCAN_ON_DURATION_NORMAL to SCAN_OFF_DURATION_NORMAL
            PowerMode.POWER_SAVER -> SCAN_ON_DURATION_POWER_SAVE to SCAN_OFF_DURATION_POWER_SAVE
            PowerMode.ULTRA_LOW_POWER -> SCAN_ON_DURATION_ULTRA_LOW to SCAN_OFF_DURATION_ULTRA_LOW
            PowerMode.PERFORMANCE -> return // No duty cycle
        }
        
        dutyCycleJob = powerScope.launch {
            while (isActive && shouldUseDutyCycle()) {
                // Scan ON period
                Log.d(TAG, "Duty cycle: Scan ON for ${onDuration}ms")
                delegate?.onScanStateChanged(true)
                delay(onDuration)
                
                // Scan OFF period (keep advertising active)
                if (isActive && shouldUseDutyCycle()) {
                    Log.d(TAG, "Duty cycle: Scan OFF for ${offDuration}ms")
                    delegate?.onScanStateChanged(false)
                    delay(offDuration)
                }
            }
        }
        
        Log.i(TAG, "Started duty cycle: ${onDuration}ms ON, ${offDuration}ms OFF")
    }
    
    private fun stopDutyCycle() {
        dutyCycleJob?.cancel()
        dutyCycleJob = null
    }
    
    private fun registerBatteryReceiver() {
        try {
            val filter = IntentFilter().apply {
                addAction(Intent.ACTION_BATTERY_CHANGED)
                addAction(Intent.ACTION_POWER_CONNECTED)
                addAction(Intent.ACTION_POWER_DISCONNECTED)
            }
            context.registerReceiver(batteryReceiver, filter)
        } catch (e: Exception) {
            Log.w(TAG, "Failed to register battery receiver: ${e.message}")
        }
    }
    
    private fun unregisterBatteryReceiver() {
        try {
            context.unregisterReceiver(batteryReceiver)
        } catch (e: Exception) {
            Log.w(TAG, "Failed to unregister battery receiver: ${e.message}")
        }
    }
}

/**
 * Delegate interface for power management callbacks
 */
interface PowerManagerDelegate {
    fun onPowerModeChanged(newMode: PowerManager.PowerMode)
    fun onScanStateChanged(shouldScan: Boolean)
}
