package com.nate.posedetection

import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
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.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.IconButton
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chaintech.videoplayer.host.MediaPlayerHost
import chaintech.videoplayer.model.ScreenResize
import chaintech.videoplayer.model.VideoPlayerConfig
import chaintech.videoplayer.ui.video.VideoPlayerComposable
import chaintech.videoplayer.util.RetrieveMediaDuration
import com.nate.posedetection.theme.AppTheme
import com.performancecoachlab.posedetection.camera.CameraView
import com.performancecoachlab.posedetection.camera.CameraViewControllerImpl
import com.performancecoachlab.posedetection.camera.DetectMode
import com.performancecoachlab.posedetection.camera.DrawableObject
import com.performancecoachlab.posedetection.camera.DrawableShape
import com.performancecoachlab.posedetection.camera.PoseFocusMode
import com.performancecoachlab.posedetection.camera.PreviewFillMode
import com.performancecoachlab.posedetection.custom.CustomObjectRespository
import com.performancecoachlab.posedetection.custom.ModelPath
import com.performancecoachlab.posedetection.custom.rememberObjectModel
import com.performancecoachlab.posedetection.encoding.VideoBuilder
import com.performancecoachlab.posedetection.encoding.createVideoBuilder
import com.performancecoachlab.posedetection.permissions.PermissionProvider
import com.performancecoachlab.posedetection.recording.AnalysisObject
import com.performancecoachlab.posedetection.recording.FrameAnalyser
import com.performancecoachlab.posedetection.recording.InputFrame
import com.performancecoachlab.posedetection.recording.AnalysisResult
import com.performancecoachlab.posedetection.recording.FrameSize
import com.performancecoachlab.posedetection.recording.extractFrame
import com.performancecoachlab.posedetection.recording.extractFrames
import com.performancecoachlab.posedetection.recording.listVideoFrameTimestamps
import com.performancecoachlab.posedetection.skeleton.Pose
import com.performancecoachlab.posedetection.skeleton.Skeleton
import com.performancecoachlab.posedetection.skeleton.SkeletonRepository
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.PlatformFile
import io.github.vinceglb.filekit.absolutePath
import io.github.vinceglb.filekit.dialogs.FileKitType
import io.github.vinceglb.filekit.dialogs.compose.rememberShareFileLauncher
import io.github.vinceglb.filekit.dialogs.openFilePicker
import io.github.vinceglb.filekit.extension
import io.github.vinceglb.filekit.filesDir
import io.github.vinceglb.filekit.path
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import kotlin.math.roundToLong
import kotlin.time.Clock
import kotlin.time.ExperimentalTime


@Composable
internal fun App() = AppTheme {
    var selectedTabIndex by remember { mutableStateOf(0) }
    val tabs = listOf("Camera Feed", "Recorded Video")

    // Apply safe-area insets once to the whole screen.
    Column(
        modifier = Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.safeDrawing)
    ) {
        // Tab row should be only as tall as needed.
        TabRow(selectedTabIndex = selectedTabIndex, modifier = Modifier.fillMaxWidth()) {
            tabs.forEachIndexed { index, title ->
                Tab(
                    selected = selectedTabIndex == index,
                    onClick = { selectedTabIndex = index },
                    text = { Text(title) })
            }
        }

        // Content always gets the remaining space.
        Box(
            modifier = Modifier.weight(1f).fillMaxWidth()
        ) {
            when (selectedTabIndex) {
                0 -> CameraSample()
                1 -> RecordedSample()
            }
        }
    }
}

@Composable
fun RecordedSample() {
    val availableModels = discoverModels()
    var selectedModel by remember(availableModels) { mutableStateOf(availableModels.firstOrNull()) }
    var videoFile: PlatformFile? = null
    var path by remember { mutableStateOf("") }
    var extension by remember { mutableStateOf("") }
    val scope = rememberCoroutineScope()
    var loading by remember { mutableStateOf(false) }
    var totalTime by remember { mutableStateOf<Long?>(null) }

    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Button(onClick = {
                scope.launch {
                    videoFile = FileKit.openFilePicker(type = FileKitType.Video)
                    loading = true
                    videoFile?.also { vid ->
                        path = vid.absolutePath()
                        extension = vid.extension
                    }
                    loading = false
                }
            }) {
                Text("Select Video")
            }

            // Model picker
            var modelMenuExpanded by remember { mutableStateOf(false) }
            Box {
                Button(onClick = { modelMenuExpanded = true }) {
                    Text(selectedModel?.name ?: "No model", fontSize = 12.sp)
                }
                DropdownMenu(
                    expanded = modelMenuExpanded,
                    onDismissRequest = { modelMenuExpanded = false }
                ) {
                    if (availableModels.isEmpty()) {
                        DropdownMenuItem(text = { Text("No models found") }, onClick = {})
                    } else {
                        availableModels.forEach { model ->
                            DropdownMenuItem(
                                text = {
                                    Row(
                                        verticalAlignment = Alignment.CenterVertically,
                                        horizontalArrangement = Arrangement.spacedBy(8.dp)
                                    ) {
                                        RadioButton(
                                            selected = selectedModel == model,
                                            onClick = null
                                        )
                                        Text(model.name)
                                    }
                                },
                                onClick = {
                                    selectedModel = model
                                    modelMenuExpanded = false
                                }
                            )
                        }
                    }
                }
            }
        }
        AnimatedContent(path) {
            if (it.isNotBlank()) {
                RetrieveMediaDuration(
                    url = path, onDurationRetrieved = { duration ->
                        totalTime = (1000 * duration).roundToLong()
                    })
                totalTime?.also { duration ->
                    FrameAnalysis(
                        url = path,
                        modifier = Modifier.weight(1f),
                        duration = duration,
                        selectedModel = selectedModel,
                    )
                }

            } else if (loading) {
                Text("Extracting Video.")
            }
        }
    }
}

@Composable
fun FrameAnalysis(
    url: String, modifier: Modifier = Modifier, duration: Long, selectedModel: NamedModel?
) {
    val coroutineScope = rememberCoroutineScope()
    var currentJob by remember { mutableStateOf<Job?>(null) }
    var image by remember { mutableStateOf<InputFrame?>(null) }
    val timeRange = Pair(0L, duration)
    var frame by remember { mutableStateOf(timeRange.first) }
    val modelPath = selectedModel?.path ?: ModelPath()
    val generalModel = rememberObjectModel(modelPath)
    val frameAnalyser by remember(modelPath) { mutableStateOf(FrameAnalyser(generalModel)) }
    var bitmap by remember { mutableStateOf<ImageBitmap?>(null) }
    val videoBuilder = remember { mutableStateOf<VideoBuilder?>(null) }
    var isRecording by remember { mutableStateOf(false) }
    val launcher = rememberShareFileLauncher()
    val file = PlatformFile(FileKit.filesDir, "video.mp4")
    var savedPath: String? by remember { mutableStateOf(null) }
    var buildTimeMs: Long? by remember { mutableStateOf(null) }
    var buildStartMs: Long? by remember { mutableStateOf(null) }
    lateinit var size: Pair<Int, Int>
    var firstFrameTimestamp: Long? by remember { mutableStateOf(null) }

    // Function to start recording
    fun startRecording() {
        isRecording = true
        buildStartMs = Clock.System.now().toEpochMilliseconds()
        coroutineScope.launch {
            try {
                val videoFile = file.path

                // Create the video builder with 30fps
                videoBuilder.value = createVideoBuilder(
                    outputPath = videoFile, fps = 30, width = size.first, height = size.second
                )
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    // Function to stop recording and finalize video
    fun stopRecording() {
        coroutineScope.launch {
            try {
                videoBuilder.value?.let { builder ->
                    savedPath = builder.finalize()
                    buildTimeMs = buildStartMs?.let {
                        Clock.System.now().toEpochMilliseconds() - it
                    }
                    videoBuilder.value = null
                    firstFrameTimestamp = null
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    val frameMap: MutableMap<String, List<Long>> = mutableMapOf()

    LaunchedEffect(url) {
        val timestamps = listVideoFrameTimestamps(url)
        frameMap[url] = timestamps
    }

    LaunchedEffect(url, frame) {
        currentJob?.cancel()
        currentJob = coroutineScope.launch {
            try {
                val extractedFrame = extractFrame(url, frame)
                extractedFrame?.let { frame ->
                    frameAnalyser.analyseFrame(frame).let { analysisResults ->
                        frame.drawAnalysisResults(analysisResults).also {
                            if (!isRecording) {
                                size = Pair(it.width, it.height)
                                startRecording()
                            }
                            if (firstFrameTimestamp == null) firstFrameTimestamp = frame.timestamp
                            val relativeTimestamp =
                                frame.timestamp - (firstFrameTimestamp ?: frame.timestamp)
                            videoBuilder.value?.addFrame(it, relativeTimestamp)
                            bitmap = it
                        }

                    }
                }
            } catch (e: Exception) {
                // Handle any error that may occur
                e.printStackTrace()
            } finally {
                val nextFrame = frameMap[url]?.let { frameTimeStamps ->
                    frameTimeStamps.firstOrNull { it > frame }
                } ?: (
                        // Fallback:
                        // If no timestamp is found (e.g., end of list or metadata missing),
                        // assume a 50 FPS video and increment by 20ms.
                        // This keeps playback and processing moving forward smoothly.
                        frame + 20L)
                nextFrame.also {
                    if (it < timeRange.second) {
                        frame = it
                    } else {
                        stopRecording()
                    }
                }
            }
        }
    }

    DisposableEffect(url) {
        onDispose {
            currentJob?.cancel()
        }
    }

    Box(modifier = modifier.fillMaxSize()) {
        buildTimeMs?.let { ms ->
            val seconds = ms / 1000.0
            // Format to one decimal place in commonMain (multiplatform) without
            // relying on platform-specific String.format.
            val display = (seconds * 10).roundToLong() / 10.0
            androidx.compose.material3.Text(
                text = "Build time: ${display}s",
                modifier = Modifier.align(androidx.compose.ui.Alignment.TopCenter)
                    .padding(top = 8.dp),
                style = androidx.compose.material3.MaterialTheme.typography.titleMedium,
            )
            // Ensure the lambda returns Unit explicitly so Kotlin can infer the
            // type parameter R of `let` in this composable context.
            Unit
        }
        if (savedPath != null) {
            val playerHost = remember {
                MediaPlayerHost(
                    mediaUrl = savedPath ?: "",
                    isLooping = true,
                    isPaused = false,
                    isMuted = true,
                    initialVideoFitMode = ScreenResize.FIT,
                )
            }
            VideoPlayerComposable(
                modifier = Modifier.padding(16.dp).fillMaxSize(),
                playerHost = playerHost,
                playerConfig = VideoPlayerConfig(
                    isSeekBarVisible = true,
                    isDurationVisible = true,
                    isFastForwardBackwardEnabled = false,
                    isMuteControlEnabled = false,
                    isSpeedControlEnabled = false,
                    isScreenLockEnabled = false,
                    isScreenResizeEnabled = false,
                    isFullScreenEnabled = false,
                    isPauseResumeEnabled = true,
                )
            )
        } else if (bitmap != null) {
            bitmap?.also {
                Image(
                    bitmap = it,
                    contentDescription = "Static Thumbnail",
                    contentScale = ContentScale.Fit,
                    modifier = Modifier.fillMaxSize()
                )
            }
        } else {
            CircularProgressIndicator(
                modifier = Modifier.align(Alignment.Center),
            )
        }
    }
}

@OptIn(ExperimentalTime::class)
@Composable
fun CameraSample() {
    val availableModels = discoverModels()
    val skeletonRepository = remember { SkeletonRepository() }
    val customObjectRespository = remember { CustomObjectRespository() }
    val skeleton by skeletonRepository.skeletonFlow.collectAsState()
    val customObjects by customObjectRespository.customObjectFlow.collectAsState()
    var permissionGranted by remember { mutableStateOf(false) }
    var recordingId: String? by remember { mutableStateOf(null) }
    var path by remember { mutableStateOf("") }
    var selectedModel by remember(availableModels) { mutableStateOf(availableModels.firstOrNull()) }
    val generalModel = rememberObjectModel(selectedModel?.path ?: ModelPath())
    var frontCamera by remember { mutableStateOf(false) }
    var ultrawide by remember { mutableStateOf(false) }
    var previewFillMode by remember { mutableStateOf(PreviewFillMode.FIT) }
    var menuExpanded by remember { mutableStateOf(false) }
    var detectMode by remember { mutableStateOf(DetectMode.BOTH) }
    var poseFocusMode by remember { mutableStateOf(PoseFocusMode.MASK) }
    val controller = remember { CameraViewControllerImpl() }

    // Experiment Mode state — buffers per-detection events into a JSON log
    // that the Mac orchestrator pulls back for the model comparison report.
    val experimentLogger = rememberExperimentLogger()
    val autoBridge = rememberExperimentAutoBridge()
    val autoSpec = LocalExperimentAutoSpec.current
    var experimentMode by remember { mutableStateOf(false) }
    var experimentRunning by remember { mutableStateOf(false) }
    var experimentStartedWallMs by remember { mutableStateOf(0L) }
    var experimentCapturedCount by remember { mutableStateOf(0) }
    var lastExperimentLogPath by remember { mutableStateOf<String?>(null) }
    val experimentEvents = remember { mutableListOf<ExperimentEvent>() }

    LaunchedEffect(experimentRunning) {
        if (!experimentRunning) return@LaunchedEffect
        // drop(1) skips the StateFlow's stale replay value so we only log
        // detections that arrive after Start was tapped.
        customObjectRespository.customObjectFlow.drop(1).collect { objs ->
            experimentEvents.add(
                ExperimentEvent(
                    wallMs = Clock.System.now().toEpochMilliseconds(),
                    objects = objs ?: emptyList(),
                )
            )
            experimentCapturedCount = experimentEvents.size
        }
    }

    // Auto-mode driver: when the activity was launched with an
    // ExperimentLaunchSpec (via intent extras → AppActivity → CompositionLocal),
    // automatically pick the model, wait until the orchestrator's wall-clock
    // target, run the buffer for the requested duration, write the JSON, and
    // (optionally) finish the activity. The orchestrator scrapes Logcat
    // (tag "ExperimentAuto") to track progress and to learn the saved path.
    LaunchedEffect(Unit) {
        val spec = autoSpec ?: return@LaunchedEffect
        autoBridge.log("entered modelName=${spec.modelName} startAt=${spec.startAtWallMs} duration=${spec.durationMs}")

        if (availableModels.isEmpty()) {
            autoBridge.log("error: no models discovered in assets")
            autoBridge.finishActivity()
            return@LaunchedEffect
        }
        val target = availableModels.firstOrNull { m ->
            val n = m.name
            n.equals(spec.modelName, ignoreCase = true) ||
                n.replace(' ', '_').equals(spec.modelName, ignoreCase = true) ||
                n.replace(' ', '_').equals(spec.modelName.replace(' ', '_'), ignoreCase = true)
        }
        if (target == null) {
            autoBridge.log("error: model not found: ${spec.modelName} (available: ${availableModels.joinToString { it.name }})")
            autoBridge.finishActivity()
            return@LaunchedEffect
        }
        experimentMode = true
        selectedModel = target

        // Wait for the pipeline to actually start emitting. drop(1) skips the
        // StateFlow's stale replay value; first() returns as soon as a fresh
        // emission lands (i.e. the model loaded, camera is producing frames,
        // and the first inference completed). Bounded by an 8s timeout in
        // case the model conflates empty results (e.g. nothing in frame).
        val firstEmission = withTimeoutOrNull(8000) {
            customObjectRespository.customObjectFlow.drop(1).first()
        }
        autoBridge.log("ready model=${target.name} firstEmissionObjects=${firstEmission?.size ?: -1}")

        val nowMs = Clock.System.now().toEpochMilliseconds()
        if (spec.startAtWallMs > nowMs) {
            delay(spec.startAtWallMs - nowMs)
        }

        // Programmatic Start — same effect as tapping the on-screen button.
        experimentEvents.clear()
        experimentCapturedCount = 0
        experimentStartedWallMs = Clock.System.now().toEpochMilliseconds()
        lastExperimentLogPath = null
        experimentRunning = true
        autoBridge.log("started wall_ms=$experimentStartedWallMs")

        delay(spec.durationMs)

        // Programmatic Stop — duplicates the manual button's serialise/write
        // sequence so both code paths produce identical JSON files.
        experimentRunning = false
        val stoppedMs = Clock.System.now().toEpochMilliseconds()
        val safeModelName = (selectedModel?.name ?: "unknown")
            .replace(' ', '_')
            .replace(Regex("[^A-Za-z0-9._-]"), "")
            .ifBlank { "unknown" }
        val runId = experimentStartedWallMs
        val filename = "${safeModelName}__${runId}.json"
        val json = buildExperimentLogJson(
            deviceModel = experimentLogger.deviceLabel,
            modelName = safeModelName,
            runId = runId,
            startedWallMs = experimentStartedWallMs,
            stoppedWallMs = stoppedMs,
            events = experimentEvents.toList(),
        )
        val writtenPath = experimentLogger.write(filename, json)
        lastExperimentLogPath = writtenPath
        autoBridge.log("stopped path=$writtenPath events=${experimentEvents.size}")

        // Brief delay so the Logcat write flushes before we tear down.
        delay(500)
        if (spec.finishOnStop) {
            autoBridge.finishActivity()
        }
    }

    PermissionProvider().apply {
        if (!hasCameraPermission()) RequestCameraPermission(onGranted = {
            permissionGranted = true
        }, onDenied = { permissionGranted = false }) else permissionGranted = true
    }

    if (permissionGranted) {
        DetectOrientation { orientation ->
            Box(modifier = Modifier.fillMaxSize()) {
                Column(modifier = Modifier.fillMaxSize()) {
                    androidx.compose.animation.AnimatedVisibility(path.isNotBlank()) {
                        val playerHost = remember(path) {
                            MediaPlayerHost(
                                mediaUrl = path,
                                isLooping = true,
                                isPaused = false,
                                isMuted = false,
                                initialVideoFitMode = ScreenResize.FIT,
                            )
                        }
                        VideoPlayerComposable(
                            modifier = Modifier.weight(1f),
                            playerHost = playerHost,
                            playerConfig = VideoPlayerConfig(
                                isSeekBarVisible = true,
                                isDurationVisible = true,
                                isFastForwardBackwardEnabled = true,
                                isMuteControlEnabled = true,
                                isSpeedControlEnabled = true,
                                isScreenLockEnabled = false,
                                isScreenResizeEnabled = true,
                                isFullScreenEnabled = true,
                                isPauseResumeEnabled = true,
                            )
                        )
                    }
                    key(orientation) {
                        CameraView(
                            skeletonRepository = skeletonRepository,
                            customObjectRepository = customObjectRespository,
                            detectMode = detectMode,
                            drawSkeleton = true,
                            drawObjects = { obj ->
                                obj.flatMap {
                                    listOf(
                                        DrawableObject(
                                            obj = it,
                                            shape = DrawableShape.LABEL,
                                            colour = Color.Yellow,
                                            style = Stroke(it.boundingBox.width * 0.1f)
                                        ), DrawableObject(
                                            obj = it,
                                            shape = DrawableShape.RECTANGLE,
                                            colour = Color.Green,
                                            style = Stroke(it.boundingBox.width * 0.1f)
                                        )
                                    )
                                }
                            },
                            objectModel = generalModel,
                            modifier = Modifier.weight(1f),
                            focusArea = Rect(0f, 0f, 0.5f, 1f),
                            poseFocusMode = poseFocusMode,
                            frontCamera = frontCamera,
                            useUltraWide = ultrawide,
                            previewFillMode = previewFillMode,
                            recordingId = recordingId,
                            controller = controller,
                            onVideoSaved = { id, url -> path = url },
                        )
                    }
                }
                Box(
                    modifier = Modifier
                        .imePadding()
                        .padding(12.dp)
                        .align(Alignment.TopEnd)
                ) {
                    IconButton(onClick = { menuExpanded = true }) {
                        Text("⋮", color = Color.White, fontSize = 22.sp)
                    }

                    DropdownMenu(
                        expanded = menuExpanded,
                        onDismissRequest = { menuExpanded = false }
                    ) {
                        // Zoom toggle
                        DropdownMenuItem(
                            text = {
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = if (ultrawide) "0.5x zoom" else "1.0x zoom")
                                    Spacer(Modifier.width(12.dp))
                                    Switch(checked = ultrawide, onCheckedChange = null)
                                }
                            },
                            onClick = { ultrawide = !ultrawide }
                        )

                        // Preview fill/crop toggle
                        DropdownMenuItem(
                            text = {
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = if (previewFillMode == PreviewFillMode.FIT) "Fill Preview" else "Fit Preview")
                                    Spacer(Modifier.width(12.dp))
                                    Switch(
                                        checked = previewFillMode == PreviewFillMode.FIT,
                                        onCheckedChange = null
                                    )
                                }
                            },
                            onClick = {
                                previewFillMode =
                                    if (previewFillMode == PreviewFillMode.FIT) PreviewFillMode.FILL else PreviewFillMode.FIT
                            }
                        )

                        // Pose focus mode toggle (mask vs crop) — only affects
                        // the pose input; object detection always sees the full frame.
                        DropdownMenuItem(
                            text = {
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = if (poseFocusMode == PoseFocusMode.CROP) "Pose: Crop focus" else "Pose: Mask focus")
                                    Spacer(Modifier.width(12.dp))
                                    Switch(
                                        checked = poseFocusMode == PoseFocusMode.CROP,
                                        onCheckedChange = null
                                    )
                                }
                            },
                            onClick = {
                                poseFocusMode =
                                    if (poseFocusMode == PoseFocusMode.MASK) PoseFocusMode.CROP else PoseFocusMode.MASK
                            }
                        )

                        HorizontalDivider()

                        DropdownMenuItem(text = {
                            Column {
                                Text(
                                    "Detection Mode",
                                    modifier = Modifier.fillMaxWidth(),
                                    textAlign = TextAlign.Center
                                )
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = "Pose")
                                    Spacer(Modifier.width(12.dp))
                                    RadioButton(
                                        selected = detectMode == DetectMode.POSE,
                                        onClick = {
                                            detectMode = DetectMode.POSE
                                        })
                                }
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = "Objects")
                                    Spacer(Modifier.width(12.dp))
                                    RadioButton(
                                        selected = detectMode == DetectMode.OBJECT,
                                        onClick = {
                                            detectMode = DetectMode.OBJECT
                                        })
                                }
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = "Both")
                                    Spacer(Modifier.width(12.dp))
                                    RadioButton(
                                        selected = detectMode == DetectMode.BOTH,
                                        onClick = {
                                            detectMode = DetectMode.BOTH
                                        })
                                }
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text(text = "None")
                                    Spacer(Modifier.width(12.dp))
                                    RadioButton(
                                        selected = detectMode == DetectMode.NONE,
                                        onClick = {
                                            detectMode = DetectMode.NONE
                                        })
                                }
                            }
                        }, onClick = {})

                        HorizontalDivider()

                        // Model picker — populated dynamically from bundled resources
                        DropdownMenuItem(text = {
                            Column {
                                Text(
                                    "Model",
                                    modifier = Modifier.fillMaxWidth(),
                                    textAlign = TextAlign.Center
                                )
                                if (availableModels.isEmpty()) {
                                    Text("No models found", fontSize = 12.sp)
                                } else {
                                    availableModels.forEach { model ->
                                        Row(
                                            horizontalArrangement = Arrangement.SpaceBetween,
                                            verticalAlignment = Alignment.CenterVertically,
                                            modifier = Modifier.fillMaxWidth()
                                        ) {
                                            Text(text = model.name, fontSize = 13.sp)
                                            Spacer(Modifier.width(12.dp))
                                            RadioButton(
                                                selected = selectedModel == model,
                                                onClick = { selectedModel = model }
                                            )
                                        }
                                    }
                                }
                            }
                        }, onClick = {})

                        HorizontalDivider()

                        // Experiment Mode toggle — when on, the bottom-of-screen
                        // Start/Stop overlay is visible and tapping Start begins
                        // buffering per-detection events for the comparison report.
                        DropdownMenuItem(
                            text = {
                                Row(
                                    horizontalArrangement = Arrangement.SpaceBetween,
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier.fillMaxWidth()
                                ) {
                                    Text("Experiment Mode")
                                    Spacer(Modifier.width(12.dp))
                                    Switch(checked = experimentMode, onCheckedChange = null)
                                }
                            },
                            onClick = {
                                val next = !experimentMode
                                experimentMode = next
                                if (!next && experimentRunning) {
                                    // Toggling off mid-run aborts without saving.
                                    experimentRunning = false
                                    experimentEvents.clear()
                                    experimentCapturedCount = 0
                                }
                            }
                        )

                        HorizontalDivider()

                        // Start/End recording button
                        DropdownMenuItem(
                            text = { Text(if (recordingId != null) "End recording" else "Start recording") },
                            onClick = {
                                if (recordingId == null) {
                                    recordingId = "${Clock.System.now().epochSeconds}"
                                } else {
                                    recordingId = null
                                }
                                // Keep menu open or close? Close feels better.
                                menuExpanded = false
                            }
                        )
                    }
                }
                // Experiment Mode overlay — bottom-center Start/Stop button.
                // Visible only when Experiment Mode is toggled on in the menu.
                if (experimentMode) {
                    Column(
                        modifier = Modifier
                            .align(Alignment.BottomCenter)
                            .padding(bottom = 24.dp),
                        horizontalAlignment = Alignment.CenterHorizontally,
                    ) {
                        Button(onClick = {
                            if (!experimentRunning) {
                                experimentEvents.clear()
                                experimentCapturedCount = 0
                                experimentStartedWallMs = Clock.System.now().toEpochMilliseconds()
                                lastExperimentLogPath = null
                                experimentRunning = true
                            } else {
                                experimentRunning = false
                                val stoppedMs = Clock.System.now().toEpochMilliseconds()
                                val safeModelName = (selectedModel?.name ?: "unknown")
                                    .replace(' ', '_')
                                    .replace(Regex("[^A-Za-z0-9._-]"), "")
                                    .ifBlank { "unknown" }
                                val runId = experimentStartedWallMs
                                val filename = "${safeModelName}__${runId}.json"
                                val json = buildExperimentLogJson(
                                    deviceModel = experimentLogger.deviceLabel,
                                    modelName = safeModelName,
                                    runId = runId,
                                    startedWallMs = experimentStartedWallMs,
                                    stoppedWallMs = stoppedMs,
                                    events = experimentEvents.toList(),
                                )
                                lastExperimentLogPath = experimentLogger.write(filename, json)
                            }
                        }) {
                            Text(if (experimentRunning) "Stop Experiment" else "Start Experiment")
                        }
                        if (experimentRunning) {
                            Text(
                                "Captured: $experimentCapturedCount events",
                                color = Color.White,
                                fontSize = 12.sp,
                                modifier = Modifier.padding(top = 4.dp),
                            )
                        }
                        lastExperimentLogPath?.let { p ->
                            Text(
                                "Saved: $p",
                                color = Color.White,
                                fontSize = 11.sp,
                                textAlign = TextAlign.Center,
                                modifier = Modifier.padding(top = 4.dp, start = 8.dp, end = 8.dp),
                            )
                        }
                    }
                }
            }
        }

    } else Text("Camera permission not granted")

    val upRightPose = Pose(
        leftShoulder = Pose.PoseRange(0.0, 40.0),
        rightShoulder = Pose.PoseRange(0.0, 40.0),
        leftHip = Pose.PoseRange(160.0, 180.0),
        rightHip = Pose.PoseRange(160.0, 180.0),
        leftKnee = Pose.PoseRange(160.0, 180.0),
        rightKnee = Pose.PoseRange(160.0, 180.0)
    )
    val starPose = Pose(
        leftShoulder = Pose.PoseRange(70.0, 110.0),
        rightShoulder = Pose.PoseRange(70.0, 110.0),
        leftHip = Pose.PoseRange(110.0, 150.0),
        rightHip = Pose.PoseRange(110.0, 150.0),
        leftKnee = Pose.PoseRange(160.0, 180.0),
        rightKnee = Pose.PoseRange(160.0, 180.0)
    )
    skeleton?.let {
        if (upRightPose.matches(it)) Text("Standing", fontSize = 15.sp)
        else if (starPose.matches(it)) Text("Star", fontSize = 15.sp)
        else Text("No Pose Detected", fontSize = 15.sp)
    }
}
