package eu.geyskens.pdfscan.ui.screens

import android.graphics.Bitmap
import android.graphics.PointF
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Button
import androidx.compose.material3.FilterChip
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import eu.geyskens.pdfscan.R
import eu.geyskens.pdfscan.ScanViewModel
import eu.geyskens.pdfscan.data.ScanFilter
import androidx.compose.foundation.Canvas
import androidx.compose.ui.geometry.Offset as GeomOffset

@Composable
fun CropScreen(vm: ScanViewModel, navController: NavController, pageId: String) {
    val page = remember(pageId) { vm.page(pageId) }
    if (page == null) {
        navController.popBackStack()
        return
    }

    var source by remember(pageId) { mutableStateOf<Bitmap?>(null) }
    androidx.compose.runtime.LaunchedEffect(pageId) { source = vm.loadSource(page) }

    // Local editable copy of the four normalized corners (TL, TR, BR, BL).
    val corners = remember(pageId) {
        page.corners.map { mutableStateOf(PointF(it.x, it.y)) }.toMutableList()
    }
    var filter by remember(pageId) { mutableStateOf(page.filter) }
    var boxSize by remember { mutableStateOf(IntSize.Zero) }
    val density = LocalDensity.current

    Column(Modifier.fillMaxSize().background(Color.Black).safeDrawingPadding()) {
        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
                .onSizeChanged { boxSize = it },
            contentAlignment = Alignment.Center,
        ) {
            val bmp = source
            if (bmp != null && boxSize != IntSize.Zero) {
                val scale = minOf(
                    boxSize.width.toFloat() / bmp.width,
                    boxSize.height.toFloat() / bmp.height,
                )
                val dispW = bmp.width * scale
                val dispH = bmp.height * scale
                val offX = (boxSize.width - dispW) / 2f
                val offY = (boxSize.height - dispH) / 2f

                fun toScreen(p: PointF) = GeomOffset(offX + p.x * dispW, offY + p.y * dispH)

                Image(
                    bitmap = bmp.asImageBitmap(),
                    contentDescription = null,
                    contentScale = ContentScale.Fit,
                    modifier = Modifier.fillMaxSize(),
                )

                // Quad outline.
                Canvas(Modifier.fillMaxSize()) {
                    val pts = corners.map { toScreen(it.value) }
                    for (i in pts.indices) {
                        val a = pts[i]
                        val b = pts[(i + 1) % pts.size]
                        drawLine(Color(0xFF388BFD), a, b, strokeWidth = 4f)
                    }
                }

                // Draggable handles.
                corners.forEachIndexed { i, cornerState ->
                    val screen = toScreen(cornerState.value)
                    val handlePx = with(density) { 32.dp.toPx() }
                    Box(
                        modifier = Modifier
                            // Position from the container's top-left, matching the Canvas
                            // coordinate space (the container uses contentAlignment = Center,
                            // which would otherwise offset handles from the middle).
                            .align(Alignment.TopStart)
                            .offset(
                                x = with(density) { (screen.x - handlePx / 2).toDp() },
                                y = with(density) { (screen.y - handlePx / 2).toDp() },
                            )
                            .size(32.dp)
                            .background(Color(0xAA388BFD), CircleShape)
                            .border(2.dp, Color.White, CircleShape)
                            .pointerInput(pageId, i, dispW, dispH) {
                                detectDragGestures { change, drag ->
                                    change.consume()
                                    val cur = cornerState.value
                                    val nx = (cur.x + drag.x / dispW).coerceIn(0f, 1f)
                                    val ny = (cur.y + drag.y / dispH).coerceIn(0f, 1f)
                                    cornerState.value = PointF(nx, ny)
                                }
                            },
                    )
                }
            }
        }

        // Filter chips.
        Row(
            Modifier.fillMaxWidth().padding(12.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            FilterOption(stringResource(R.string.filter_color), filter == ScanFilter.COLOR) { filter = ScanFilter.COLOR }
            FilterOption(stringResource(R.string.filter_grayscale), filter == ScanFilter.GRAYSCALE) { filter = ScanFilter.GRAYSCALE }
            FilterOption(stringResource(R.string.filter_bw), filter == ScanFilter.BLACK_WHITE) { filter = ScanFilter.BLACK_WHITE }
        }

        Row(
            Modifier.fillMaxWidth().padding(horizontal = 12.dp).padding(bottom = 16.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            OutlinedButton(onClick = { vm.rotate(pageId) }, modifier = Modifier.weight(1f)) {
                Text(stringResource(R.string.rotate))
            }
            OutlinedButton(
                onClick = {
                    val full = eu.geyskens.pdfscan.data.Page.fullFrameCorners()
                    full.forEachIndexed { i, p -> corners[i].value = PointF(p.x, p.y) }
                },
                modifier = Modifier.weight(1f),
            ) { Text(stringResource(R.string.reset)) }
            Button(
                onClick = {
                    vm.updateCorners(pageId, corners.map { PointF(it.value.x, it.value.y) })
                    vm.setFilter(pageId, filter)
                    navController.popBackStack()
                },
                modifier = Modifier.weight(1f),
            ) { Text(stringResource(R.string.apply)) }
        }
    }
}

@Composable
private fun FilterOption(label: String, selected: Boolean, onClick: () -> Unit) {
    FilterChip(selected = selected, onClick = onClick, label = { Text(label) })
}
