package com.agentui.desktop

import android.app.PendingIntent
import android.app.PictureInPictureParams
import android.app.RemoteAction
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.Rational
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : TauriActivity() {

    companion object {
        private const val TAG = "AgentUI"
        private const val ACTION_PIP_MIC = "com.agentui.desktop.PIP_MIC"
        private const val ACTION_PIP_EXPAND = "com.agentui.desktop.PIP_EXPAND"
        private const val PIP_REQUEST_CODE_MIC = 2001
        private const val PIP_REQUEST_CODE_EXPAND = 2002
    }

    private var pendingRoute: String? = null
    private var pendingVoiceTerminal: String? = null

    private val pipReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                ACTION_PIP_MIC -> {
                    Log.d(TAG, "PiP mic button pressed")
                    val voiceIntent = Intent(context, VoiceCommandActivity::class.java).apply {
                        action = Intent.ACTION_VOICE_COMMAND
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    }
                    startActivity(voiceIntent)
                }
                ACTION_PIP_EXPAND -> {
                    Log.d(TAG, "PiP expand button pressed")
                    val expandIntent = Intent(context, MainActivity::class.java).apply {
                        addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP)
                    }
                    startActivity(expandIntent)
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        syncServerUrlToPrefs()
        injectSafeAreaInsets()
        handleWidgetIntent(intent)
        handleVoiceIntent(intent)
        registerPipReceiver()
        injectJsBridge()
    }

    override fun onDestroy() {
        super.onDestroy()
        try { unregisterReceiver(pipReceiver) } catch (_: Exception) {}
    }

    override fun onNewIntent(intent: android.content.Intent) {
        super.onNewIntent(intent)
        handleWidgetIntent(intent)
        handleVoiceIntent(intent)
    }

    override fun onResume() {
        super.onResume()
        syncServerUrlToPrefs()
        pendingRoute?.let { route ->
            pendingRoute = null
            navigateWebView(route)
        }
    }

    override fun onPictureInPictureModeChanged(
        isInPictureInPictureMode: Boolean,
        newConfig: Configuration
    ) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
        Log.d(TAG, "PiP mode changed: $isInPictureInPictureMode")
    }

    // ── PiP ──

    private fun enterPipIfSupported() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            try {
                val actions = buildPipActions()
                val builder = PictureInPictureParams.Builder()
                    .setAspectRatio(Rational(9, 16))
                    .setActions(actions)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    builder.setSeamlessResizeEnabled(true)
                }
                enterPictureInPictureMode(builder.build())
            } catch (e: Exception) {
                Log.w(TAG, "Failed to enter PiP: $e")
            }
        }
    }

    private fun buildPipActions(): List<RemoteAction> {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return emptyList()

        val actions = mutableListOf<RemoteAction>()

        val micIntent = PendingIntent.getBroadcast(
            this, PIP_REQUEST_CODE_MIC,
            Intent(ACTION_PIP_MIC).setPackage(packageName),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        actions.add(RemoteAction(
            Icon.createWithResource(this, android.R.drawable.ic_btn_speak_now),
            "Voice", "Send voice command",
            micIntent
        ))

        val expandIntent = PendingIntent.getBroadcast(
            this, PIP_REQUEST_CODE_EXPAND,
            Intent(ACTION_PIP_EXPAND).setPackage(packageName),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        actions.add(RemoteAction(
            Icon.createWithResource(this, android.R.drawable.ic_menu_view),
            "Open", "Open full app",
            expandIntent
        ))

        return actions
    }

    private fun registerPipReceiver() {
        val filter = IntentFilter().apply {
            addAction(ACTION_PIP_MIC)
            addAction(ACTION_PIP_EXPAND)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(pipReceiver, filter, RECEIVER_NOT_EXPORTED)
        } else {
            registerReceiver(pipReceiver, filter)
        }
    }

    // ── JS Bridge (exposes AgentUI.enterPip() to the WebView) ──

    private fun injectJsBridge() {
        window.decorView.postDelayed({
            try {
                val webView = findWebView(window.decorView)
                if (webView != null) {
                    webView.addJavascriptInterface(JsBridge(), "AgentUI")
                    Log.d(TAG, "JS bridge injected (AgentUI.enterPip)")
                } else {
                    // Retry once more after delay
                    window.decorView.postDelayed({
                        val wv = findWebView(window.decorView)
                        if (wv != null) {
                            wv.addJavascriptInterface(JsBridge(), "AgentUI")
                            Log.d(TAG, "JS bridge injected on retry")
                        }
                    }, 1000)
                }
            } catch (e: Exception) {
                Log.w(TAG, "Failed to inject JS bridge: $e")
            }
        }, 500)
    }

    inner class JsBridge {
        @JavascriptInterface
        fun enterPip() {
            runOnUiThread { enterPipIfSupported() }
        }
    }

    // ── Voice intent → navigate to transcript page ──

    private fun handleVoiceIntent(intent: android.content.Intent?) {
        if (intent?.action == "com.agentui.desktop.VOICE_TERMINAL") {
            val sessionId = intent.getStringExtra("ephemeralSessionId") ?: ""
            Log.d(TAG, "Voice intent → navigate to transcript-debug, terminal=$sessionId")
            pendingVoiceTerminal = sessionId
            pollForWebViewAndNavigate(sessionId, 0)
        }
    }

    private fun pollForWebViewAndNavigate(ephemeralSessionId: String, attempt: Int) {
        if (attempt > 15) {
            Log.w(TAG, "Gave up waiting for WebView after $attempt attempts")
            pendingVoiceTerminal = null
            return
        }

        val webView = try { findWebView(window.decorView) } catch (_: Exception) { null }

        if (webView != null) {
            // Navigate to transcript-debug page and tell it which terminal to focus
            val js = "window.__VOICE_OPEN_TERMINAL__ && window.__VOICE_OPEN_TERMINAL__('$ephemeralSessionId')"
            webView.evaluateJavascript(js, null)
            pendingVoiceTerminal = null
            Log.d(TAG, "Voice navigate dispatched (attempt $attempt): $ephemeralSessionId")
        } else {
            Log.d(TAG, "WebView not ready (attempt $attempt), retrying in 200ms")
            window.decorView.postDelayed({
                pollForWebViewAndNavigate(ephemeralSessionId, attempt + 1)
            }, 200)
        }
    }

    // ── Widget intent ──

    private fun handleWidgetIntent(intent: android.content.Intent?) {
        val terminalIndex = intent?.getIntExtra("terminalIndex", -1) ?: -1
        if (terminalIndex > 0) {
            val route = "/transcript-debug/$terminalIndex"
            Log.d(TAG, "Widget click → navigate to $route")
            pendingRoute = route
            navigateWebView(route)
        }
    }

    // ── WebView helpers ──

    private fun navigateWebView(route: String) {
        try {
            val webView = findWebView(window.decorView)
            if (webView != null) {
                val js = "window.__WIDGET_NAVIGATE__ && window.__WIDGET_NAVIGATE__('$route') || (window.location.href = '$route')"
                webView.evaluateJavascript(js, null)
                pendingRoute = null
            }
        } catch (e: Exception) {
            Log.w(TAG, "Failed to navigate WebView: $e")
        }
    }

    private fun injectSafeAreaInsets() {
        val decorView = window.decorView
        ViewCompat.setOnApplyWindowInsetsListener(decorView) { view, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            val density = resources.displayMetrics.density
            val topDp = systemBars.top / density
            val bottomDp = systemBars.bottom / density
            val leftDp = systemBars.left / density
            val rightDp = systemBars.right / density
            val js = """
                document.documentElement.style.setProperty('--sat', '${topDp}px');
                document.documentElement.style.setProperty('--sab', '${bottomDp}px');
                document.documentElement.style.setProperty('--sal', '${leftDp}px');
                document.documentElement.style.setProperty('--sar', '${rightDp}px');
            """.trimIndent()
            try {
                val webView = view.findViewWithTag<WebView>("tauri_webview")
                    ?: view.findViewById<WebView>(android.R.id.content)?.let { findWebView(it) }
                webView?.evaluateJavascript(js, null)
                Log.d(TAG, "Injected safe-area: top=${topDp}dp bottom=${bottomDp}dp")
            } catch (e: Exception) {
                Log.w(TAG, "Failed to inject safe-area insets: $e")
            }
            ViewCompat.onApplyWindowInsets(view, insets)
        }
    }

    private fun findWebView(view: android.view.View): WebView? {
        if (view is WebView) return view
        if (view is android.view.ViewGroup) {
            for (i in 0 until view.childCount) {
                val found = findWebView(view.getChildAt(i))
                if (found != null) return found
            }
        }
        return null
    }

    private fun syncServerUrlToPrefs() {
        val url = ServerConfig.getServerUrl(this)
        Log.d(TAG, "syncServerUrlToPrefs: resolved url=$url")
    }
}
