package com.inou.clawdnode.service

import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import com.inou.clawdnode.ClawdNodeApp
import com.inou.clawdnode.R
import com.inou.clawdnode.protocol.*
import com.inou.clawdnode.ui.MainActivity

/**
 * Main foreground service that maintains Gateway connection
 * and coordinates all ClawdNode functionality.
 */
class NodeService : Service() {
    
    private val tag = "NodeService"
    private val binder = LocalBinder()
    
    private lateinit var gatewayClient: GatewayClient
    
    private var isConnected = false
    
    // Callbacks for UI updates
    var onConnectionChange: ((Boolean) -> Unit)? = null
    
    inner class LocalBinder : Binder() {
        fun getService(): NodeService = this@NodeService
    }
    
    override fun onBind(intent: Intent?): IBinder = binder
    
    override fun onCreate() {
        super.onCreate()
        Log.i(tag, "NodeService created")
        
        gatewayClient = GatewayClient(
            onCommand = { command -> handleCommand(command) },
            onConnectionChange = { connected ->
                isConnected = connected
                updateNotification()
                onConnectionChange?.invoke(connected)
            }
        )
    }
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.i(tag, "NodeService starting")
        
        // Start as foreground service
        startForeground(NOTIFICATION_ID, createNotification())
        
        // Connect to gateway
        if (ClawdNodeApp.instance.tokenStore.isConfigured) {
            gatewayClient.connect()
        } else {
            Log.w(tag, "Gateway not configured, waiting for setup")
        }
        
        return START_STICKY
    }
    
    override fun onDestroy() {
        Log.i(tag, "NodeService destroyed")
        gatewayClient.disconnect()
        ClawdNodeApp.instance.auditLog.log("SERVICE_STOP", "NodeService destroyed")
        super.onDestroy()
    }
    
    // ========================================
    // PUBLIC API
    // ========================================
    
    fun connect() {
        gatewayClient.connect()
    }
    
    fun disconnect() {
        gatewayClient.disconnect()
    }
    
    fun isConnected() = isConnected
    
    fun sendEvent(event: NodeEvent) {
        gatewayClient.send(event)
    }
    
    // ========================================
    // COMMAND HANDLING
    // ========================================
    
    private fun handleCommand(command: NodeCommand) {
        Log.d(tag, "Handling command: ${command::class.simpleName}")
        
        try {
            when (command) {
                is ScreenshotCommand -> handleScreenshot(command)
                is NotificationActionCommand -> handleNotificationAction(command)
                is NotificationDismissCommand -> handleNotificationDismiss(command)
                is CallAnswerCommand -> handleCallAnswer(command)
                is CallRejectCommand -> handleCallReject(command)
                is CallSilenceCommand -> handleCallSilence(command)
                is CallSpeakCommand -> handleCallSpeak(command)
                is CallHangupCommand -> handleCallHangup(command)
            }
        } catch (e: Exception) {
            Log.e(tag, "Error handling command", e)
            command.requestId?.let { 
                gatewayClient.sendResponse(it, false, error = e.message)
            }
        }
    }
    
    private fun handleScreenshot(cmd: ScreenshotCommand) {
        // TODO: Implement screenshot capture via MediaProjection
        Log.d(tag, "Screenshot requested - not yet implemented")
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, false, error = "Screenshot not yet implemented")
        }
    }
    
    private fun handleNotificationAction(cmd: NotificationActionCommand) {
        // Delegate to NotificationListener
        NotificationManager.triggerAction(cmd.notificationId, cmd.action, cmd.text)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("triggered" to true))
        }
    }
    
    private fun handleNotificationDismiss(cmd: NotificationDismissCommand) {
        NotificationManager.dismiss(cmd.notificationId)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("dismissed" to true))
        }
    }
    
    private fun handleCallAnswer(cmd: CallAnswerCommand) {
        CallManager.answer(cmd.callId, cmd.greeting)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("answered" to true))
        }
    }
    
    private fun handleCallReject(cmd: CallRejectCommand) {
        CallManager.reject(cmd.callId, cmd.reason)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("rejected" to true))
        }
    }
    
    private fun handleCallSilence(cmd: CallSilenceCommand) {
        CallManager.silence(cmd.callId)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("silenced" to true))
        }
    }
    
    private fun handleCallSpeak(cmd: CallSpeakCommand) {
        CallManager.speak(cmd.callId, cmd.text, cmd.voice)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("speaking" to true))
        }
    }
    
    private fun handleCallHangup(cmd: CallHangupCommand) {
        CallManager.hangup(cmd.callId)
        cmd.requestId?.let {
            gatewayClient.sendResponse(it, true, payload = mapOf("hungup" to true))
        }
    }
    
    // ========================================
    // NOTIFICATION
    // ========================================
    
    private fun createNotification(): Notification {
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        
        val status = if (isConnected) "Connected to Gateway" else "Disconnected"
        
        return NotificationCompat.Builder(this, ClawdNodeApp.CHANNEL_SERVICE)
            .setContentTitle("ClawdNode")
            .setContentText(status)
            .setSmallIcon(R.drawable.ic_notification)
            .setOngoing(true)
            .setContentIntent(pendingIntent)
            .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
            .build()
    }
    
    private fun updateNotification() {
        val notification = createNotification()
        val manager = getSystemService(NOTIFICATION_SERVICE) as android.app.NotificationManager
        manager.notify(NOTIFICATION_ID, notification)
    }
    
    companion object {
        const val NOTIFICATION_ID = 1001
    }
}

/**
 * Singleton managers for coordinating with system services.
 * These get populated by the respective listener services.
 */
object NotificationManager {
    private var listener: com.inou.clawdnode.notifications.NotificationListener? = null
    
    fun register(listener: com.inou.clawdnode.notifications.NotificationListener) {
        this.listener = listener
    }
    
    fun triggerAction(notificationId: String, action: String, text: String?) {
        listener?.triggerAction(notificationId, action, text)
    }
    
    fun dismiss(notificationId: String) {
        listener?.dismissNotification(notificationId)
    }
}

object CallManager {
    private var callService: com.inou.clawdnode.calls.VoiceCallService? = null
    
    fun register(service: com.inou.clawdnode.calls.VoiceCallService) {
        this.callService = service
    }
    
    fun answer(callId: String, greeting: String?) {
        callService?.answerCall(callId, greeting)
    }
    
    fun reject(callId: String, reason: String?) {
        callService?.rejectCall(callId)
    }
    
    fun silence(callId: String) {
        callService?.silenceCall(callId)
    }
    
    fun speak(callId: String, text: String, voice: String?) {
        callService?.speakIntoCall(callId, text)
    }
    
    fun hangup(callId: String) {
        callService?.hangupCall(callId)
    }
}
