package com.lazy.emulate

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.view.KeyEvent
import android.view.MotionEvent
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.navigation.compose.rememberNavController
import com.lazy.emulate.data.PreferencesManager
import com.lazy.emulate.data.repository.GameRepository
import com.lazy.emulate.emulation.EmulationEngine
import com.lazy.emulate.input.ButtonMappingManager
import com.lazy.emulate.input.ControllerManager
import com.lazy.emulate.ui.navigation.EmulateNavGraph
import com.lazy.emulate.ui.theme.EmulateTheme

class MainActivity : ComponentActivity() {

    private lateinit var controllerManager: ControllerManager
    private lateinit var gameRepository: GameRepository

    private val usbAttachReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action != UsbManager.ACTION_USB_DEVICE_ATTACHED) return
            @Suppress("DEPRECATION")
            val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
            if (device != null) controllerManager.onUsbDeviceAttached(device)
        }
    }
    lateinit var preferencesManager: PreferencesManager
        private set
    lateinit var buttonMappingManager: ButtonMappingManager
        private set

    @OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        requestAllFilesPermission()

        preferencesManager = PreferencesManager(this)
        buttonMappingManager = ButtonMappingManager(preferencesManager)
        controllerManager = ControllerManager(this, buttonMappingManager)
        gameRepository = GameRepository(this)
        EmulationEngine.buttonMappingManager = buttonMappingManager

        // Note: we deliberately do NOT call handleUsbAttachIntent(intent) here.
        // start() hasn't registered the permission receiver yet, and onResume() will
        // do a usbManager.deviceList sweep that picks up any device that's already attached.
        setContent {
            EmulateTheme {
                val windowSizeClass = calculateWindowSizeClass(this)
                val navController = rememberNavController()

                EmulateNavGraph(
                    navController = navController,
                    windowSizeClass = windowSizeClass,
                    gameRepository = gameRepository,
                    controllerManager = controllerManager,
                    preferencesManager = preferencesManager,
                    buttonMappingManager = buttonMappingManager
                )
            }
        }
    }

    override fun onResume() {
        super.onResume()
        controllerManager.start()
        // Silently receive USB attach events while the app is foregrounded — no dialogs.
        val filter = IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(usbAttachReceiver, filter, RECEIVER_NOT_EXPORTED)
        } else {
            @Suppress("UnspecifiedRegisterReceiverFlag")
            registerReceiver(usbAttachReceiver, filter)
        }
        // Also sweep for any matching device that's already connected when we resume.
        controllerManager.tryClaimAlreadyConnectedUsb()
        if (Environment.isExternalStorageManager()) {
            gameRepository.scanGameFolders()
        }
    }

    override fun onPause() {
        super.onPause()
        try { unregisterReceiver(usbAttachReceiver) } catch (_: Throwable) {}
        controllerManager.stop()
    }

    override fun onDestroy() {
        super.onDestroy()
        controllerManager.releaseClaim()
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleUsbAttachIntent(intent)
    }

    private fun handleUsbAttachIntent(intent: Intent?) {
        if (intent?.action != UsbManager.ACTION_USB_DEVICE_ATTACHED) return
        @Suppress("DEPRECATION")
        val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
        if (device != null) {
            controllerManager.onUsbDeviceAttached(device)
        }
    }

    private fun requestAllFilesPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
            val intent = Intent(
                Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
                Uri.parse("package:$packageName")
            )
            startActivity(intent)
        }
    }

    // Compose's root view installs its own key-event handler and will consume events
    // before Activity.onKeyDown/onKeyUp run. Intercept at dispatchKeyEvent instead so
    // gamepad input always reaches ControllerManager.
    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        if (controllerManager.handleKeyEvent(event)) return true
        return super.dispatchKeyEvent(event)
    }

    override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
        if (controllerManager.handleMotionEvent(event)) return true
        return super.dispatchGenericMotionEvent(event)
    }
}
