package com.rosetta.messenger.ui.qr

import android.Manifest
import android.content.pm.PackageManager
import android.util.Size
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import compose.icons.TablerIcons
import compose.icons.tablericons.X
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean

data class QrScanResult(
    val type: QrResultType,
    val payload: String // publicKey, inviteString, or username
)

enum class QrResultType { PROFILE, GROUP, UNKNOWN }

fun parseQrContent(raw: String): QrScanResult {
    val trimmed = raw.trim()
    return when {
        trimmed.startsWith("rosetta://profile/") ->
            QrScanResult(QrResultType.PROFILE, trimmed.removePrefix("rosetta://profile/"))
        trimmed.startsWith("rosetta://group/") ->
            QrScanResult(QrResultType.GROUP, trimmed.removePrefix("rosetta://group/"))
        trimmed.startsWith("https://rosetta.im/@") ->
            QrScanResult(QrResultType.PROFILE, trimmed.removePrefix("https://rosetta.im/@"))
        trimmed.startsWith("https://rosetta.im/u/") ->
            QrScanResult(QrResultType.PROFILE, trimmed.removePrefix("https://rosetta.im/u/"))
        trimmed.startsWith("#group:") ->
            QrScanResult(QrResultType.GROUP, trimmed)
        else -> QrScanResult(QrResultType.UNKNOWN, trimmed)
    }
}

@Composable
fun QrScannerScreen(
    onBack: () -> Unit,
    onResult: (QrScanResult) -> Unit
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val mainExecutor = remember(context) { ContextCompat.getMainExecutor(context) }
    val cameraExecutor = remember { Executors.newSingleThreadExecutor() }
    val barcodeScanner = remember { BarcodeScanning.getClient() }

    var hasCameraPermission by remember {
        mutableStateOf(ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
    }
    val permissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {
        hasCameraPermission = it
    }

    LaunchedEffect(Unit) {
        if (!hasCameraPermission) permissionLauncher.launch(Manifest.permission.CAMERA)
    }

    var previewView by remember { mutableStateOf<PreviewView?>(null) }
    var cameraProvider by remember { mutableStateOf<ProcessCameraProvider?>(null) }
    var previewUseCase by remember { mutableStateOf<Preview?>(null) }
    var analysisUseCase by remember { mutableStateOf<ImageAnalysis?>(null) }
    val scannedOnce = remember { AtomicBoolean(false) }
    var isClosing by remember { mutableStateOf(false) }

    fun requestClose() {
        if (isClosing) return
        isClosing = true
        runCatching { analysisUseCase?.clearAnalyzer() }
        onBack()
    }

    fun dispatchResult(result: QrScanResult) {
        if (isClosing) return
        isClosing = true
        runCatching { analysisUseCase?.clearAnalyzer() }
        onResult(result)
    }

    DisposableEffect(Unit) {
        onDispose {
            runCatching { analysisUseCase?.clearAnalyzer() }
            runCatching {
                val provider = cameraProvider
                val preview = previewUseCase
                val analyzer = analysisUseCase
                if (provider != null && preview != null && analyzer != null) {
                    provider.unbind(preview, analyzer)
                } else {
                    provider?.unbindAll()
                }
            }
            runCatching { barcodeScanner.close() }
            runCatching { cameraExecutor.shutdownNow() }
        }
    }

    DisposableEffect(hasCameraPermission, lifecycleOwner, previewView, isClosing) {
        val localPreviewView = previewView
        if (!hasCameraPermission || localPreviewView == null || isClosing) {
            onDispose {}
        } else {
            val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
            val listener = Runnable {
                val provider = runCatching { cameraProviderFuture.get() }.getOrNull() ?: return@Runnable
                cameraProvider = provider

                val preview = Preview.Builder().build().also {
                    it.setSurfaceProvider(localPreviewView.surfaceProvider)
                }
                val analyzer = ImageAnalysis.Builder()
                    .setTargetResolution(Size(1280, 720))
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()

                analyzer.setAnalyzer(cameraExecutor) { imageProxy ->
                    @androidx.annotation.OptIn(androidx.camera.core.ExperimentalGetImage::class)
                    val mediaImage = imageProxy.image
                    if (mediaImage == null || scannedOnce.get() || isClosing) {
                        imageProxy.close()
                        return@setAnalyzer
                    }

                    val image =
                        InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)

                    barcodeScanner.process(image)
                        .addOnSuccessListener { barcodes ->
                            if (scannedOnce.get() || isClosing) return@addOnSuccessListener
                            val parsedResult =
                                barcodes.firstNotNullOfOrNull { barcode ->
                                    if (barcode.valueType != Barcode.TYPE_TEXT &&
                                        barcode.valueType != Barcode.TYPE_URL
                                    ) {
                                        return@firstNotNullOfOrNull null
                                    }
                                    val raw = barcode.rawValue ?: return@firstNotNullOfOrNull null
                                    val parsed = parseQrContent(raw)
                                    parsed.takeIf { it.type != QrResultType.UNKNOWN }
                                }

                            if (parsedResult != null && scannedOnce.compareAndSet(false, true)) {
                                dispatchResult(parsedResult)
                            }
                        }
                        .addOnCompleteListener { imageProxy.close() }
                }

                runCatching {
                    val oldPreview = previewUseCase
                    val oldAnalyzer = analysisUseCase
                    if (oldPreview != null && oldAnalyzer != null) {
                        provider.unbind(oldPreview, oldAnalyzer)
                    }
                }
                previewUseCase = preview
                analysisUseCase = analyzer

                runCatching {
                    provider.bindToLifecycle(
                        lifecycleOwner,
                        CameraSelector.DEFAULT_BACK_CAMERA,
                        preview,
                        analyzer
                    )
                }
            }

            cameraProviderFuture.addListener(listener, mainExecutor)

            onDispose {
                runCatching { analysisUseCase?.clearAnalyzer() }
                runCatching {
                    val provider = cameraProvider
                    val preview = previewUseCase
                    val analyzer = analysisUseCase
                    if (provider != null && preview != null && analyzer != null) {
                        provider.unbind(preview, analyzer)
                    }
                }
            }
        }
    }

    Box(modifier = Modifier.fillMaxSize().background(Color.Black)) {
        if (hasCameraPermission) {
            AndroidView(
                factory = { ctx ->
                    PreviewView(ctx).also { created ->
                        previewView = created
                    }
                },
                update = { updated -> previewView = updated },
                modifier = Modifier.fillMaxSize()
            )
        } else {
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Text("Camera permission required", color = Color.White, fontSize = 16.sp)
            }
        }

        // Viewfinder overlay
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            Box(
                modifier = Modifier
                    .size(250.dp)
                    .border(2.dp, Color.White.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
            )
        }

        // Top bar
        Row(
            modifier = Modifier.fillMaxWidth().statusBarsPadding().padding(16.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            IconButton(onClick = ::requestClose) {
                Icon(TablerIcons.X, contentDescription = "Close", tint = Color.White, modifier = Modifier.size(28.dp))
            }
            Spacer(modifier = Modifier.weight(1f))
            Text("Scan QR Code", fontSize = 18.sp, fontWeight = FontWeight.SemiBold, color = Color.White)
            Spacer(modifier = Modifier.weight(1f))
            Spacer(modifier = Modifier.width(48.dp))
        }

        // Bottom hint
        Text(
            text = "Point your camera at a Rosetta QR code",
            color = Color.White.copy(alpha = 0.7f),
            fontSize = 14.sp,
            textAlign = TextAlign.Center,
            modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 80.dp).fillMaxWidth()
        )
    }
}
