package com.phan_tech.flutter_overlay_apps

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import io.flutter.FlutterInjector
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.FlutterEngineGroup
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.*
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

const val mainAppMethodChannel: String = "com.phan_tech/flutter_overlay_apps"
const val overlayAppMethodChannel: String = "com.phan_tech/flutter_overlay_apps/overlay"
const val overlayAppMessageChannel: String = "com.phan_tech/flutter_overlay_apps/overlay/messenger"

/** FlutterOverlayAppsPlugin */
class FlutterOverlayAppsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, BasicMessageChannel.MessageHandler<Any?> {
    private lateinit var channel: MethodChannel
    private lateinit var messenger: BasicMessageChannel<Any?>
    private lateinit var context: Context
    private var activity: Activity? = null

    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        activity = binding.activity
        context = binding.activity.applicationContext
        WindowSetup.messenger = messenger
        WindowSetup.messenger!!.setMessageHandler(this)
        
        val engineGroup = FlutterEngineGroup(context)
        val dartEntrypoint = DartExecutor.DartEntrypoint(
            FlutterInjector.instance().flutterLoader().findAppBundlePath(),
            "showOverlay"
        )
        val engine = engineGroup.createAndRunEngine(context, dartEntrypoint)
        FlutterEngineCache.getInstance().put("my_engine_id", engine)
    }

    override fun onDetachedFromActivityForConfigChanges() {
        activity = null
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        activity = binding.activity
    }

    override fun onDetachedFromActivity() {
        activity = null
    }

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, mainAppMethodChannel)
        channel.setMethodCallHandler(this)

        messenger = BasicMessageChannel(flutterPluginBinding.binaryMessenger, overlayAppMessageChannel, JSONMessageCodec.INSTANCE)
        messenger.setMessageHandler(this)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        val currentActivity = activity
        if (currentActivity == null) {
            result.error("activity_not_attached", "Activity is not attached", null)
            return
        }

        when (call.method) {
            "showOverlay" -> {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                    result.error("1", "SDK version is lower than 23", "Requires Android SDK 23 and above")
                } else if (!checkPermissions()) {
                    requestPermissions()
                } else {
                    val height = call.argument<Int>("height")
                    val width = call.argument<Int>("width")
                    val alignment = call.argument<String>("alignment")
                    val closeOnBackButton = call.argument<Boolean>("closeOnBackButton")

                    WindowSetup.width = width ?: -1
                    WindowSetup.height = height ?: -1
                    WindowSetup.closeOnBackButton = closeOnBackButton ?: true
                    WindowSetup.setGravityFromAlignment(alignment ?: "center")
                    currentActivity.startService(Intent(context, OverlayService::class.java))
                    result.success(true)
                }
            }
            else -> {
                result.notImplemented()
            }
        }
    }

    override fun onMessage(message: Any?, reply: BasicMessageChannel.Reply<Any?>) {
        val engine = FlutterEngineCache.getInstance().get("my_engine_id")
        if (engine != null) {
            val overlayMessageChannel = BasicMessageChannel(engine.dartExecutor, overlayAppMessageChannel, JSONMessageCodec.INSTANCE)
            overlayMessageChannel.send(message, reply)
        } else {
            reply.reply(null)
        }
    }

    @RequiresApi(Build.VERSION_CODES.M)
    private fun checkPermissions(): Boolean {
        return Settings.canDrawOverlays(context)
    }

    @RequiresApi(Build.VERSION_CODES.M)
    private fun requestPermissions() {
        activity?.let {
            it.startActivity(
                Intent(
                    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:${it.packageName}")
                )
            )
        }
    }
}
