package chat.pyramid.pyramid

import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import androidx.core.app.RemoteInput
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.plugin.common.MethodChannel
import java.io.File

class MainActivity : FlutterActivity() {
    private val channel = "chat.pyramid.pyramid/install"

    // ── Share-Target (Teilen nach Pyramid) ────────────────────────────────────
    // Extracts shared text/streams from SEND/SEND_MULTIPLE intents. Streams are
    // copied into cacheDir because Flutter cannot read content:// URIs directly.
    private fun extractShare(intent: Intent?): Map<String, Any?>? {
        if (intent == null) return null
        val action = intent.action
        if (action != Intent.ACTION_SEND && action != Intent.ACTION_SEND_MULTIPLE) return null
        val text = intent.getStringExtra(Intent.EXTRA_TEXT)
        val uris = mutableListOf<Uri>()
        if (action == Intent.ACTION_SEND) {
            val u: Uri? = if (Build.VERSION.SDK_INT >= 33)
                intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
            else @Suppress("DEPRECATION") intent.getParcelableExtra(Intent.EXTRA_STREAM)
            if (u != null) uris.add(u)
        } else {
            val list: ArrayList<Uri>? = if (Build.VERSION.SDK_INT >= 33)
                intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)
            else @Suppress("DEPRECATION") intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
            if (list != null) uris.addAll(list)
        }
        if (text.isNullOrEmpty() && uris.isEmpty()) return null
        val paths = uris.mapNotNull { copyShareToCache(it) }
        return mapOf("text" to text, "paths" to paths)
    }

    private fun copyShareToCache(uri: Uri): String? {
        return try {
            val name = contentResolver.query(uri, null, null, null, null)?.use { c ->
                val idx = c.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
                if (idx >= 0 && c.moveToFirst()) c.getString(idx) else null
            } ?: "shared_${System.currentTimeMillis()}"
            val safe = name.replace(Regex("[^A-Za-z0-9._-]"), "_")
            val outFile = File(cacheDir, "share_${System.currentTimeMillis()}_$safe")
            val stream = contentResolver.openInputStream(uri) ?: return null
            stream.use { input ->
                outFile.outputStream().use { input.copyTo(it) }
            }
            outFile.absolutePath
        } catch (e: Exception) {
            Log.e("PYRAMID-SHARE", "copyShareToCache failed: ${e.message}")
            null
        }
    }

    // Extract reply text from an intent using all known key patterns.
    private fun extractReply(intent: Intent?): Pair<String?, String?> {
        if (intent == null) return Pair(null, null)
        // Only treat intents with our REPLY action as reply intents.
        if (intent.action != ReplyReceiver.ACTION_REPLY) return Pair(null, null)
        val remoteInputResults = RemoteInput.getResultsFromIntent(intent)
        val replyText: String? =
            remoteInputResults?.let { bundle ->
                // Primary key must match RemoteInput.Builder key in NotificationHelper.
                bundle.getCharSequence(ReplyReceiver.REMOTE_INPUT_KEY)?.toString()?.trim()
                    ?: bundle.keySet()?.firstOrNull()?.let { bundle.getCharSequence(it)?.toString()?.trim() }
            }
            ?: intent.getStringExtra(ReplyReceiver.REMOTE_INPUT_KEY)
            ?: intent.getStringExtra("input")
        val payload = intent.getStringExtra(ReplyReceiver.EXTRA_ROOM_ID)
            ?: intent.getStringExtra("payload")
        return Pair(replyText, payload)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        // If this Activity was launched to handle a notification reply (cold start),
        // apply a fully transparent theme BEFORE super.onCreate so no UI is ever
        // drawn. The Flutter engine still initialises (needed for E2EE send via SDK)
        // but the window remains invisible.
        val (replyText, _) = extractReply(intent)
        if (!replyText.isNullOrEmpty()) {
            setTheme(R.style.ReplyHandlerTheme)
            Log.e("PYRAMID-INTENT", "onCreate: reply launch detected — transparent theme applied")
        }
        super.onCreate(savedInstanceState)
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        // Cache so ReplyReceiver can call back into Dart without starting a new engine.
        FlutterEngineCache.getInstance().put("main", flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    // Flutter asks for the room_id embedded in the launch intent (cold-start tap).
                    "getInitialRoomId" -> {
                        result.success(intent?.getStringExtra("room_id"))
                    }
                    // Cold-start share: app was launched via "Teilen nach Pyramid".
                    "getInitialShare" -> {
                        val share = extractShare(intent)
                        if (share != null) {
                            result.success(share)
                            intent = Intent() // clear so it's delivered only once
                        } else {
                            result.success(null)
                        }
                    }
                    // Flutter asks for any inline reply that arrived on cold-start.
                    // When the app is killed and the user presses Reply, Android calls
                    // onCreate (not onNewIntent), so the reply text is in the launch intent.
                    "getInitialReply" -> {
                        val (replyText, payload) = extractReply(intent)
                        Log.e("PYRAMID-INTENT", "getInitialReply: replyText=${replyText?.take(20)} payload=$payload")
                        if (!replyText.isNullOrEmpty() && !payload.isNullOrEmpty()) {
                            result.success(mapOf("room_id" to payload, "text" to replyText))
                            // Clear the launch intent so a second getInitialReply call returns null.
                            intent = Intent()
                        } else {
                            result.success(null)
                        }
                    }
                    // Supported CPU ABIs in preference order, so the updater can
                    // pick the matching split APK from a release.
                    "getAbis" -> {
                        result.success(Build.SUPPORTED_ABIS.toList())
                    }
                    "installApk" -> {
                        val path = call.argument<String>("path")
                        if (path == null) {
                            result.error("INVALID_ARG", "path is null", null)
                            return@setMethodCallHandler
                        }
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
                            !packageManager.canRequestPackageInstalls()) {
                            val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
                                data = Uri.parse("package:$packageName")
                                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                            }
                            startActivity(intent)
                            result.error("PERMISSION_REQUIRED", "install_permission", null)
                            return@setMethodCallHandler
                        }
                        try {
                            val file = File(path)
                            val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                FileProvider.getUriForFile(
                                    this,
                                    "${applicationContext.packageName}.fileprovider",
                                    file
                                )
                            } else {
                                Uri.fromFile(file)
                            }
                            val intent = Intent(Intent.ACTION_VIEW).apply {
                                setDataAndType(uri, "application/vnd.android.package-archive")
                                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                            }
                            startActivity(intent)
                            result.success(null)
                        } catch (e: Exception) {
                            result.error("INSTALL_ERROR", e.message, null)
                        }
                    }
                    "openNotificationSettings" -> {
                        val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                            Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
                                putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
                            }
                        } else {
                            Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                                data = Uri.fromParts("package", packageName, null)
                            }
                        }
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        startActivity(intent)
                        result.success(null)
                    }
                    "openBatterySettings" -> {
                        val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
                            data = Uri.parse("package:$packageName")
                            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        }
                        try {
                            startActivity(intent)
                        } catch (e: Exception) {
                            val fallback = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
                                data = Uri.fromParts("package", packageName, null)
                                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                            }
                            startActivity(fallback)
                        }
                        result.success(null)
                    }
                    "minimizeApp" -> {
                        moveTaskToBack(true)
                        result.success(null)
                    }
                    "showNativeNotification" -> {
                        val title   = call.argument<String>("title")   ?: ""
                        val body    = call.argument<String>("body")    ?: ""
                        val roomId  = call.argument<String>("roomId")  ?: ""
                        val notifId = call.argument<Int>("notifId")    ?: NotificationHelper.stableId(roomId)
                        if (roomId.isNotEmpty()) {
                            NotificationHelper.show(this, title, body, roomId, notifId)
                            result.success(null)
                        } else {
                            result.error("INVALID_ARG", "roomId missing", null)
                        }
                    }
                    else -> result.notImplemented()
                }
            }
    }

    // Called when the app is already running (background) and a notification action
    // fires — reply and tap both arrive here via onNewIntent (singleTop + SINGLE_TOP flag).
    override fun onNewIntent(intent: Intent) {
        // Zero-duration transition for all notification-driven intents.
        overridePendingTransition(0, 0)

        super.onNewIntent(intent)
        setIntent(intent)

        Log.e("PYRAMID-INTENT", "onNewIntent action=${intent.action}")

        // ── Reply action ──────────────────────────────────────────────────────
        if (intent.action == ReplyReceiver.ACTION_REPLY) {
            val (replyText, payload) = extractReply(intent)
            Log.e("PYRAMID-INTENT", "reply: replyText=${replyText?.take(20)} payload=$payload")
            if (!replyText.isNullOrEmpty() && !payload.isNullOrEmpty()) {
                flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger ->
                    MethodChannel(messenger, channel).invokeMethod(
                        "replyFromNotification",
                        mapOf("room_id" to payload, "text" to replyText),
                    )
                }
            }
            // Always send back immediately — never show the app UI for a reply.
            moveTaskToBack(true)
            overridePendingTransition(0, 0)
            return
        }

        // ── Share action — app already running, user shared from another app ──
        val share = extractShare(intent)
        if (share != null) {
            flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger ->
                MethodChannel(messenger, channel).invokeMethod("sharedContent", share)
            }
            return
        }

        // ── Tap action — open the room ────────────────────────────────────────
        val roomId = intent.getStringExtra("room_id") ?: return
        flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger ->
            MethodChannel(messenger, channel).invokeMethod(
                "openRoom",
                mapOf("room_id" to roomId),
            )
        }
    }
}
