package me.khodak.mfa

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL

class MainActivity : AppCompatActivity() {

    private lateinit var icon: ImageView
    private lateinit var statusText: TextView
    private lateinit var subText: TextView
    private lateinit var actionButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        icon = findViewById(R.id.icon)
        statusText = findViewById(R.id.statusText)
        subText = findViewById(R.id.subText)
        actionButton = findViewById(R.id.actionButton)

        val uri = intent?.data
        if (uri?.scheme == "homemfa") {
            handleDeepLink(uri)
        } else {
            showSetupScreen()
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        val uri = intent.data
        if (uri?.scheme == "homemfa") {
            handleDeepLink(uri)
        }
    }

    private fun handleDeepLink(uri: Uri) {
        val action = uri.host   // "approve" or "deny"
        val token = uri.getQueryParameter("token")

        if (token.isNullOrBlank() || action == null) {
            showResult(false, "Invalid request", "Missing token or action")
            scheduleClose(2000)
            return
        }

        if (action == "deny") {
            sendDecision(token, "deny")
            return
        }

        // action == "approve" — require biometrics
        val canAuth = BiometricManager.from(this)
            .canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)

        if (canAuth != BiometricManager.BIOMETRIC_SUCCESS) {
            showResult(false, "No biometrics enrolled", "Go to phone Settings → Security → Fingerprint to enroll, then try again.")
            actionButton.text = "Open Security Settings"
            actionButton.visibility = View.VISIBLE
            actionButton.setOnClickListener {
                startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
            }
            return
        }

        showBiometricPrompt(token)
    }

    private fun showSetupScreen() {
        val canAuth = BiometricManager.from(this)
            .canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)

        icon.setImageResource(R.drawable.ic_fingerprint)
        icon.clearColorFilter()

        when (canAuth) {
            BiometricManager.BIOMETRIC_SUCCESS -> {
                statusText.text = "Homelab MFA — Ready"
                subText.text = "Biometrics enrolled. When you log in via Authentik, tap Approve in the ntfy notification — this app will open and ask for your fingerprint."
                subText.visibility = View.VISIBLE
                icon.setColorFilter(ContextCompat.getColor(this, R.color.green))
                actionButton.text = "Test Biometric"
                actionButton.visibility = View.VISIBLE
                actionButton.setOnClickListener { testBiometric() }
            }
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
                statusText.text = "Setup Required"
                subText.text = "No fingerprint or face enrolled. Enroll in Settings → Security → Fingerprint to activate biometric protection."
                subText.visibility = View.VISIBLE
                icon.setColorFilter(ContextCompat.getColor(this, R.color.red))
                actionButton.text = "Open Security Settings"
                actionButton.visibility = View.VISIBLE
                actionButton.setOnClickListener {
                    startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
                }
            }
            else -> {
                statusText.text = "Biometrics unavailable"
                subText.text = "This device doesn't support biometric authentication (code $canAuth)."
                subText.visibility = View.VISIBLE
                icon.setColorFilter(ContextCompat.getColor(this, R.color.red))
                actionButton.visibility = View.GONE
            }
        }
    }

    private fun testBiometric() {
        val executor = ContextCompat.getMainExecutor(this)
        val prompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                icon.setImageResource(R.drawable.ic_check)
                icon.setColorFilter(ContextCompat.getColor(this@MainActivity, R.color.green))
                statusText.text = "Biometric works!"
                subText.text = "You're all set. Authentik logins will now require your fingerprint to approve."
                actionButton.visibility = View.GONE
            }
            override fun onAuthenticationFailed() {}
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                showSetupScreen()
            }
        })

        prompt.authenticate(
            BiometricPrompt.PromptInfo.Builder()
                .setTitle("Test Biometric")
                .setSubtitle("Confirm this works before relying on it")
                .setAllowedAuthenticators(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
                .build()
        )
    }

    private fun showBiometricPrompt(token: String) {
        val executor = ContextCompat.getMainExecutor(this)
        val prompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                sendDecision(token, "approve")
            }
            override fun onAuthenticationFailed() {}
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                if (errorCode == BiometricPrompt.ERROR_USER_CANCELED ||
                    errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON ||
                    errorCode == BiometricPrompt.ERROR_CANCELED) {
                    showResult(false, "Cancelled", "Login not approved")
                } else {
                    showResult(false, "Auth error", errString.toString())
                }
                scheduleClose(2000)
            }
        })

        prompt.authenticate(
            BiometricPrompt.PromptInfo.Builder()
                .setTitle("Approve Login")
                .setSubtitle("Confirm your identity to allow access")
                .setAllowedAuthenticators(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
                .build()
        )
    }

    private fun sendDecision(token: String, action: String) {
        val topic = if (action == "approve") "mfa-approve" else "mfa-deny"
        val body = "$action:$token"
        showResult(null, "Sending...", "")

        CoroutineScope(Dispatchers.IO).launch {
            val success = try {
                val conn = URL("https://ntfy.khodak.me/$topic").openConnection() as HttpURLConnection
                conn.requestMethod = "POST"
                conn.doOutput = true
                conn.connectTimeout = 8000
                conn.readTimeout = 8000
                OutputStreamWriter(conn.outputStream).use { it.write(body) }
                conn.responseCode in 200..299
            } catch (e: Exception) { false }

            withContext(Dispatchers.Main) {
                if (action == "approve") {
                    if (success) showResult(true, "Approved", "Login allowed")
                    else showResult(false, "Network error", "Could not reach server")
                } else {
                    if (success) showResult(false, "Denied", "Login blocked")
                    else showResult(false, "Network error", "Could not reach server")
                }
                scheduleClose(1800)
            }
        }
    }

    private fun showResult(approved: Boolean?, title: String, subtitle: String) {
        statusText.text = title
        subText.text = subtitle
        subText.visibility = if (subtitle.isEmpty()) View.GONE else View.VISIBLE
        actionButton.visibility = View.GONE

        when (approved) {
            true  -> {
                icon.setImageResource(R.drawable.ic_check)
                icon.setColorFilter(ContextCompat.getColor(this, R.color.green))
            }
            false -> {
                icon.setImageResource(R.drawable.ic_close)
                icon.setColorFilter(ContextCompat.getColor(this, R.color.red))
            }
            null  -> {
                icon.setImageResource(R.drawable.ic_fingerprint)
                icon.clearColorFilter()
            }
        }
    }

    private fun scheduleClose(delayMs: Long) {
        CoroutineScope(Dispatchers.Main).launch {
            delay(delayMs)
            finish()
        }
    }
}
