package com.platform101xp.unity

import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.Configuration
import android.os.Bundle
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import com.platform101xp.plugin.Platform101XPAdvertisingListenerBuilder
import com.platform101xp.plugin.Platform101XPEventListenerBuilder
import com.platform101xp.plugin.Platform101XPUnityActionListener
import com.platform101xp.sdk.Platform101XP
import com.unity3d.player.IUnityPlayerLifecycleEvents
import com.unity3d.player.UnityPlayerForActivityOrService

class Platform101xpActivity : AppCompatActivity(), IUnityPlayerLifecycleEvents {
    companion object {
        const val UNITY_OBJECT_NAME = "PluginService"
    }

    // don't change the name of this variable; referenced from native code
    protected var mUnityPlayer: UnityPlayerForActivityOrService? = null

    // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player
    // The command line arguments are passed as a string, separated by spaces
    // UnityPlayerActivity calls this from 'onCreate'
    // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan
    // See https://docs.unity3d.com/Manual/CommandLineArguments.html
    // @param cmdLine the current command line arguments, may be null
    // @return the modified command line string or null
    protected fun updateUnityCommandLineArguments(cmdLine: String?): String?{
        return cmdLine
    }

    // Setup activity layout
    protected override fun onCreate(savedInstanceState: Bundle?) {
        if (mUnityPlayer != null) {
            return
        }

        requestWindowFeature(Window.FEATURE_NO_TITLE)
        super.onCreate(savedInstanceState)
        supportActionBar?.hide()

        val cmdLine: String? = updateUnityCommandLineArguments(intent.getStringExtra("unity"))
        intent.putExtra("unity", cmdLine)

        val unityPlayer = UnityPlayerForActivityOrService(this, this)
        setContentView(unityPlayer.frameLayout)
        unityPlayer.frameLayout.requestFocus()
        mUnityPlayer = unityPlayer

        // 101XP
        val unityActionListener = object : Platform101XPUnityActionListener {
            override fun onSendAction(methodName: String, params: String) {
                UnityPlayerForActivityOrService.UnitySendMessage(UNITY_OBJECT_NAME, methodName, params)
            }
        }
        Platform101XPAdvertisingListenerBuilder.Build(unityActionListener)
        Platform101XPEventListenerBuilder.Build(unityActionListener)
        Platform101XP.onCreate(this)
    }

    // 101XP
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Platform101XP.onActivityResult(requestCode, resultCode, data)
    }
    
    // 101XP
    override fun onBackPressed() {
        super.onBackPressed()
        Platform101XP.backPressed()
    }

    // When Unity player unloaded move task to background
    override fun onUnityPlayerUnloaded() {
        moveTaskToBack(true)
    }

    // Callback before Unity player process is killed
    override fun onUnityPlayerQuitted() {
    }

    protected override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        // To support deep linking, we need to make sure that the client can get access to
        // the last sent intent. The clients access this through a JNI api that allows them
        // to get the intent set on launch. To update that after launch we have to manually
        // replace the intent with the one caught here.
        setIntent(intent)
        mUnityPlayer?.newIntent(intent)
    }

    // Quit Unity
    protected override fun onDestroy() {
        super.onDestroy()
        mUnityPlayer?.destroy()
        mUnityPlayer = null
    }

    // Pause Unity
    protected override fun onPause() {
        super.onPause()
        mUnityPlayer?.onPause()
    }

    // Resume Unity
    protected override fun onResume() {
        super.onResume()
        mUnityPlayer?.onResume()
    }

    // Low Memory Unity
    override fun onLowMemory() {
        super.onLowMemory()
        mUnityPlayer?.onTrimMemory(UnityPlayerForActivityOrService.MemoryUsage.Critical);
    }

    // Trim Memory Unity
    @SuppressLint("SwitchIntDef")
    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
        when (level) {
            TRIM_MEMORY_RUNNING_MODERATE -> mUnityPlayer?.onTrimMemory(
                UnityPlayerForActivityOrService.MemoryUsage.Medium
            )
            TRIM_MEMORY_RUNNING_LOW -> mUnityPlayer?.onTrimMemory(
                UnityPlayerForActivityOrService.MemoryUsage.High
            )
            TRIM_MEMORY_RUNNING_CRITICAL -> mUnityPlayer?.onTrimMemory(
                UnityPlayerForActivityOrService.MemoryUsage.Critical
            )
        }
    }

    // This ensures the layout will be correct.
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        mUnityPlayer?.configurationChanged(newConfig)
    }

    // Notify Unity of the focus change.
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        mUnityPlayer?.windowFocusChanged(hasFocus)
    }

    // Pass any events not handled by (unfocused) views straight to UnityPlayer
    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
        return mUnityPlayer?.injectEvent(event) ?: super.onKeyUp(keyCode, event)
    }

    // Pass any events not handled by (unfocused) views straight to UnityPlayer
    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        return mUnityPlayer?.injectEvent(event) ?: super.onKeyDown(keyCode, event)
    }

    // Pass any events not handled by (unfocused) views straight to UnityPlayer
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        return mUnityPlayer?.injectEvent(event) ?: super.onTouchEvent(event)
    }

    override fun onGenericMotionEvent(event: MotionEvent?): Boolean {
        return mUnityPlayer?.injectEvent(event) ?: super.onGenericMotionEvent(event)
    }
}
