/*
 * Hermes Node Android
 * Copyright (C) 2026 Stefy Lanza <stefy@nexlab.net>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package net.nexlab.hermesnodeandroid

import android.Manifest
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.widget.Button
import android.widget.CheckBox
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast

class MainActivity : Activity() {
    private lateinit var gatewayUrl: EditText
    private lateinit var nodeName: EditText
    private lateinit var token: EditText
    private lateinit var insecureTls: CheckBox
    private lateinit var computerControl: CheckBox
    private lateinit var desktopObserve: CheckBox
    private lateinit var audioControl: CheckBox
    private lateinit var cameraControl: CheckBox
    private lateinit var browserControl: CheckBox
    private lateinit var notificationAccess: CheckBox
    private lateinit var execControl: CheckBox
    private lateinit var statusView: TextView

    private val statusReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) = refreshStatus()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        buildUi()
        loadConfigIntoUi()
        refreshStatus()
        requestNotificationPermissionIfNeeded()
    }

    override fun onResume() {
        super.onResume()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(statusReceiver, IntentFilter(StatusStore.ACTION_STATUS_CHANGED), RECEIVER_NOT_EXPORTED)
        } else {
            @Suppress("DEPRECATION")
            registerReceiver(statusReceiver, IntentFilter(StatusStore.ACTION_STATUS_CHANGED))
        }
        refreshStatus()
    }

    override fun onPause() {
        runCatching { unregisterReceiver(statusReceiver) }
        super.onPause()
    }

    private fun buildUi() {
        val root = LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            setPadding(32, 32, 32, 32)
        }
        val title = TextView(this).apply {
            text = "Hermes Node Android"
            textSize = 24f
        }
        val subtitle = TextView(this).apply {
            text = "Reverse-connect this Android phone to the Hermes Node Gateway."
            textSize = 14f
        }
        gatewayUrl = edit("Gateway URL", "wss://lisa.nexlab.net:8765")
        nodeName = edit("Node name", "android-phone")
        token = edit("Gateway token", "")
        insecureTls = checkbox("Allow self-signed/untrusted gateway TLS", true)
        computerControl = checkbox("computer_control: launch apps / open URLs", true)
        desktopObserve = checkbox("desktop_observe: screen/status info", true)
        audioControl = checkbox("audio_control: audio status", true)
        cameraControl = checkbox("camera_control: camera frame/video capture", true)
        browserControl = checkbox("browser_control: launch/open browser + screenshot fallback", false)
        notificationAccess = checkbox("notification_access: read active notifications", false)
        execControl = checkbox("exec (dangerous; disabled backend)", false)
        statusView = TextView(this).apply {
            textSize = 14f
            setPadding(0, 24, 0, 24)
        }

        val save = Button(this).apply {
            text = "Save config"
            setOnClickListener { saveConfig(showToast = true) }
        }
        val start = Button(this).apply {
            text = "Save & start node"
            setOnClickListener {
                val config = saveConfig(showToast = false)
                val error = config.validationError()
                if (error != null) {
                    Toast.makeText(this@MainActivity, error, Toast.LENGTH_LONG).show()
                } else {
                    startService(Intent(this@MainActivity, HermesNodeService::class.java).setAction(HermesNodeService.ACTION_START))
                    Toast.makeText(this@MainActivity, "Hermes node starting", Toast.LENGTH_SHORT).show()
                }
            }
        }
        val stop = Button(this).apply {
            text = "Stop node"
            setOnClickListener {
                startService(Intent(this@MainActivity, HermesNodeService::class.java).setAction(HermesNodeService.ACTION_STOP))
                Toast.makeText(this@MainActivity, "Hermes node stopping", Toast.LENGTH_SHORT).show()
            }
        }
        val refresh = Button(this).apply {
            text = "Refresh status"
            setOnClickListener { refreshStatus() }
        }
        val permissions = Button(this).apply {
            text = "Grant camera/microphone permissions"
            setOnClickListener { requestRuntimePermissions() }
        }
        val accessibility = Button(this).apply {
            text = "Open Accessibility settings"
            setOnClickListener { startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) }
        }
        val screenshotConsent = Button(this).apply {
            text = "Grant screenshot consent"
            setOnClickListener { requestScreenshotConsent() }
        }
        val videoCaptureTest = Button(this).apply {
            text = "Start visible video capture test"
            setOnClickListener { startVideoCaptureTest() }
        }

        listOf<View>(
            title, subtitle, gatewayUrl, nodeName, token, insecureTls,
            computerControl, desktopObserve, audioControl, cameraControl,
            browserControl, notificationAccess, execControl, save, start, stop, refresh,
            permissions, accessibility, screenshotConsent, videoCaptureTest, notificationSettingsButton(), statusView,
        ).forEach { root.addView(it) }
        setContentView(ScrollView(this).apply { addView(root) })
    }

    private fun edit(hint: String, value: String): EditText = EditText(this).apply {
        this.hint = hint
        setText(value)
        setSingleLine(true)
    }

    private fun checkbox(label: String, checked: Boolean): CheckBox = CheckBox(this).apply {
        text = label
        isChecked = checked
    }

    private fun notificationSettingsButton(): Button = Button(this).apply {
        text = "Open notification access settings"
        setOnClickListener { startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")) }
    }

    private fun loadConfigIntoUi() {
        val config = ConfigStore.load(this)
        gatewayUrl.setText(config.gatewayUrl)
        nodeName.setText(config.nodeName)
        token.setText(config.token)
        insecureTls.isChecked = config.insecureTls
        computerControl.isChecked = config.enableComputerControl
        desktopObserve.isChecked = config.enableDesktopObserve
        audioControl.isChecked = config.enableAudioControl
        cameraControl.isChecked = config.enableCameraControl
        browserControl.isChecked = config.enableBrowserControl
        notificationAccess.isChecked = config.enableNotificationAccess
        execControl.isChecked = config.enableExec
    }

    private fun saveConfig(showToast: Boolean): NodeConfig {
        val config = NodeConfig(
            gatewayUrl = gatewayUrl.text.toString(),
            token = token.text.toString(),
            nodeName = nodeName.text.toString(),
            enableExec = execControl.isChecked,
            enableComputerControl = computerControl.isChecked,
            enableDesktopObserve = desktopObserve.isChecked,
            enableAudioControl = audioControl.isChecked,
            enableCameraControl = cameraControl.isChecked,
            enableBrowserControl = browserControl.isChecked,
            enableNotificationAccess = notificationAccess.isChecked,
            insecureTls = insecureTls.isChecked,
        )
        ConfigStore.save(this, config)
        if (showToast) Toast.makeText(this, "Config saved", Toast.LENGTH_SHORT).show()
        return config
    }

    private fun refreshStatus() {
        statusView.text = "Status:\n${StatusStore.snapshot(this)}"
    }

    private fun requestNotificationPermissionIfNeeded() {
        if (Build.VERSION.SDK_INT >= 33 && checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 100)
        }
    }

    private fun requestRuntimePermissions() {
        val needed = mutableListOf<String>()
        if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) needed += Manifest.permission.CAMERA
        if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) needed += Manifest.permission.RECORD_AUDIO
        if (Build.VERSION.SDK_INT >= 33 && checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) needed += Manifest.permission.POST_NOTIFICATIONS
        if (needed.isEmpty()) {
            Toast.makeText(this, "Camera/microphone permissions already granted", Toast.LENGTH_SHORT).show()
        } else {
            requestPermissions(needed.toTypedArray(), 101)
        }
    }

    private fun requestScreenshotConsent() {
        val mgr = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        startActivityForResult(mgr.createScreenCaptureIntent(), 200)
    }

    private fun startVideoCaptureTest() {
        val payload = org.json.JSONObject()
            .put("request_id", "manual-test-${System.currentTimeMillis()}")
            .put("node_name", nodeName.text.toString().ifBlank { "android-phone" })
            .put("duration_ms", 3000L)
            .put("width", 1280)
            .put("height", 720)
        VideoCaptureSessionStore.savePending(this, payload)
        startActivity(Intent(this, VideoCaptureActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    }

    @Deprecated("Deprecated platform callback, still the compatible MediaProjection result path")
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 200) {
            if (resultCode == RESULT_OK && data != null) {
                AndroidRuntimeGrants.setMediaProjection(resultCode, data)
                Toast.makeText(this, "Screenshot consent granted for this app process", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Screenshot consent denied", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
