package top.yeij.cyrene.service

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.service.voice.VoiceInteractionSession
import android.util.Log
import android.view.View
import android.view.WindowManager
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import android.content.res.Configuration
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.runBlocking
import org.koin.core.context.GlobalContext
import top.yeij.cyrene.MainActivity
import top.yeij.cyrene.data.local.PreferencesDataStore
import top.yeij.cyrene.ui.overlay.OverlayContent
import top.yeij.cyrene.ui.theme.CyreneTheme
import top.yeij.cyrene.util.Constants
import top.yeij.cyrene.util.RuntimeLog
import top.yeij.cyrene.viewmodel.OverlayViewModel

class CyreneVoiceInteractionSession(context: Context) :
    VoiceInteractionSession(context), LifecycleOwner, SavedStateRegistryOwner {

    private val lifecycleRegistry = LifecycleRegistry(this)
    override val lifecycle: Lifecycle get() = lifecycleRegistry

    private val savedStateRegistryController = SavedStateRegistryController.create(this)
    override val savedStateRegistry: SavedStateRegistry get() = savedStateRegistryController.savedStateRegistry

    // Resolved eagerly with fallback — lazy would silently crash composition on failure
    private var overlayViewModel: OverlayViewModel? = null
        private set

    init {
        savedStateRegistryController.performAttach()
        savedStateRegistryController.performRestore(null)
    }

    private fun resolveViewModel(): OverlayViewModel? {
        return try {
            GlobalContext.get().get<OverlayViewModel>()
        } catch (e: Throwable) {
            Log.e(TAG, "Failed to resolve OverlayViewModel from Koin", e)
            null
        }
    }

    override fun onCreateContentView(): View {
        Log.d(TAG, "onCreateContentView called")
        RuntimeLog.general("overlay", "onCreateContentView")
        overlayViewModel = resolveViewModel()
        if (overlayViewModel == null) {
            Log.w(TAG, "ViewModel unavailable — overlay will be static")
            RuntimeLog.general("overlay", "ViewModel unavailable, overlay static")
        }

        lifecycleRegistry.currentState = Lifecycle.State.CREATED
        val vm = overlayViewModel
        val session = this@CyreneVoiceInteractionSession

        val (darkTheme, themeColorKey) = runBlocking {
            val prefs = GlobalContext.get().get<PreferencesDataStore>()
            val mode = prefs.themeMode.firstOrNull()
            val color = prefs.themeColor.firstOrNull() ?: "pink"
            val dark = when (mode) {
                "light" -> false
                "dark" -> true
                else -> {
                    val nightMode = session.context.resources.configuration.uiMode and
                        Configuration.UI_MODE_NIGHT_MASK
                    nightMode == Configuration.UI_MODE_NIGHT_YES
                }
            }
            Pair(dark, color)
        }

        return ComposeView(context).apply {
            // Configure window as soon as view is attached — before system overrides flags
            addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View) {
                    session.configureWindow()
                }
                override fun onViewDetachedFromWindow(v: View) {}
            })
            setViewTreeLifecycleOwner(session)
            setViewTreeSavedStateRegistryOwner(session)
            setContent {
                CyreneTheme(
                    darkTheme = darkTheme,
                    presetKey = themeColorKey,
                    useDynamicColor = themeColorKey == "monet",
                ) {
                    if (vm != null) {
                        OverlayContent(
                            onDismiss = { finish() },
                            onNavigateToMain = {
                                val intent = Intent(context, MainActivity::class.java).apply {
                                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                                }
                                context.startActivity(intent)
                            },
                            viewModel = vm,
                        )
                    }
                }
            }
        }
    }

    override fun onShow(args: Bundle?, showFlags: Int) {
        super.onShow(args, showFlags)
        RuntimeLog.general("overlay", "onShow, vm=${overlayViewModel != null}")
        lifecycleRegistry.currentState = Lifecycle.State.STARTED

        // Defer window config — system may override softInputMode after onShow returns
        try {
            val method = VoiceInteractionSession::class.java.getDeclaredMethod("getWindow")
            method.isAccessible = true
            val w = method.invoke(this) as? android.view.Window
            w?.decorView?.post { configureWindow() }
        } catch (e: Throwable) {
            // Fallback: configure immediately
            configureWindow()
        }

        // Only read screen content if user enabled it in settings (default off)
        val autoScreenContext = try {
            val prefs: PreferencesDataStore = GlobalContext.get().get()
            runBlocking { prefs.autoScreenContext.firstOrNull() } ?: false
        } catch (_: Throwable) {
            false
        }
        if (autoScreenContext) {
            val screenContent = CyreneAccessibilityService.getScreenContent()
            if (screenContent.isNotBlank()) {
                overlayViewModel?.sendScreenContext(screenContent)
                RuntimeLog.general("overlay", "Screen context sent, len=${screenContent.length}")
            }
        }
    }

    fun configureWindow() {
        try {
            val method = VoiceInteractionSession::class.java.getDeclaredMethod("getWindow")
            method.isAccessible = true
            val w = method.invoke(this) as? android.view.Window ?: return
            // Transparent window so the underlying screen is visible through the overlay
            w.setBackgroundDrawable(android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT))
            w.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
            w.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
            w.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
            Log.d(TAG, "Window configured: transparent bg, translucent status/nav")
        } catch (e: Throwable) {
            Log.w(TAG, "Failed to configure window: ${e.message}")
        }
    }

    override fun onHide() {
        RuntimeLog.general("overlay", "onHide")
        lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
        super.onHide()
        overlayViewModel?.finish()
    }

    companion object {
        private const val TAG = "CyreneVIS-Session"
    }
}
