package com.keylightpiano.pianotimeline.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material.icons.filled.RepeatOne
import androidx.compose.material.icons.filled.Shuffle
import androidx.compose.material.icons.filled.Stop
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.keylightpiano.pianotimeline.R
import com.keylightpiano.pianotimeline.domain.Recording
import com.keylightpiano.pianotimeline.player.PlaybackState

/**
 * Compact now-playing bar pinned to the bottom. Shows the active track's
 * artist/title, a play/pause toggle, a thin progress bar, and a dismiss button.
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MiniPlayer(
    recording: Recording?,
    playback: PlaybackState,
    onTogglePlayPause: () -> Unit,
    onSeek: (Long) -> Unit,
    onPrevious: () -> Unit,
    onNext: () -> Unit,
    onStop: () -> Unit,
    shuffle: Boolean,
    repeatMode: RepeatMode,
    onToggleShuffle: () -> Unit,
    onCycleRepeat: () -> Unit,
    modifier: Modifier = Modifier,
    // When something else sits BELOW the mini-player (e.g. the offline banner),
    // that lower element should own the navigation-bar inset instead — otherwise
    // both would reserve nav-bar space and leave a gap. Callers pass false then.
    applyNavigationBarInset: Boolean = true
) {
    Surface(
        modifier = modifier.fillMaxWidth(),
        color = MaterialTheme.colorScheme.surfaceVariant,
        shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
        tonalElevation = 3.dp,
        shadowElevation = 8.dp
    ) {
        // Inset the content above the system navigation bar so the controls
        // aren't hidden under it (the surface background still fills to the edge).
        // Skipped when a lower bar (offline banner) owns the inset instead.
        Column(
            modifier = if (applyNavigationBarInset)
                Modifier.windowInsetsPadding(WindowInsets.navigationBars)
            else Modifier
        ) {
            // Stopped = nothing loaded (fresh start, or after Stop). The bar stays
            // visible but shows an empty/reset state with controls inert.
            val stopped = recording == null

            // While the user is dragging, we hold a local position so the thumb
            // follows the finger instead of snapping back to the polled playhead.
            var isDragging by remember { mutableStateOf(false) }
            var dragValueMs by remember { mutableFloatStateOf(0f) }

            val duration = playback.durationMs.coerceAtLeast(1L)
            val sliderValue = if (isDragging) dragValueMs
                              else playback.positionMs.toFloat().coerceIn(0f, duration.toFloat())

            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 8.dp, end = 12.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                // Shuffle + repeat, moved here from the top bar. Compact so they
                // don't eat too much of the seek bar's width.
                IconButton(onClick = onToggleShuffle, modifier = Modifier.size(32.dp)) {
                    Icon(
                        imageVector = Icons.Default.Shuffle,
                        contentDescription = stringResource(R.string.cd_shuffle),
                        tint = if (shuffle) Color(0xFF70D66B)
                               else MaterialTheme.colorScheme.onSurfaceVariant,
                        modifier = Modifier.size(18.dp)
                    )
                }
                IconButton(onClick = onCycleRepeat, modifier = Modifier.size(32.dp)) {
                    Icon(
                        imageVector = if (repeatMode == RepeatMode.ONE)
                            Icons.Default.RepeatOne else Icons.Default.Repeat,
                        contentDescription = stringResource(R.string.cd_repeat),
                        tint = if (repeatMode == RepeatMode.OFF)
                            MaterialTheme.colorScheme.onSurfaceVariant
                        else Color(0xFF70D66B),
                        modifier = Modifier.size(18.dp)
                    )
                }
                Spacer(Modifier.width(4.dp))

                Slider(
                    value = sliderValue,
                    enabled = !stopped,
                    onValueChange = { v ->
                        isDragging = true
                        dragValueMs = v
                    },
                    onValueChangeFinished = {
                        onSeek(dragValueMs.toLong())
                        isDragging = false
                    },
                    valueRange = 0f..duration.toFloat(),
                    modifier = Modifier
                        .weight(1f)
                        .padding(end = 8.dp),
                    thumb = {
                        // Wider than tall, rounded — a little "pill" instead of a circle.
                        Box(
                            modifier = Modifier
                                .size(width = 12.dp, height = 13.dp)
                                .clip(RoundedCornerShape(6.dp))
                                .background(Color(0xFF23A300))
                        )
                    },
                    track = { sliderState ->
                        val fraction = if (sliderState.valueRange.endInclusive > sliderState.valueRange.start) {
                            (sliderState.value - sliderState.valueRange.start) /
                                (sliderState.valueRange.endInclusive - sliderState.valueRange.start)
                        } else 0f

                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(2.dp)  // ~half the default 4dp track
                        ) {
                            // Inactive (full width, dim)
                            Box(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .height(2.dp)
                                    .clip(RoundedCornerShape(1.dp))
                                    .background(MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f))
                            )
                            // Active (filled portion)
                            Box(
                                modifier = Modifier
                                    .fillMaxWidth(fraction.coerceIn(0f, 1f))
                                    .height(2.dp)
                                    .clip(RoundedCornerShape(1.dp))
                                    .background(Color(0xFF25B300))
                            )
                        }
                    }
                )

                Text(
                    text = "${formatTime(playback.positionMs)} / ${formatTime(playback.durationMs)}",
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                    maxLines = 1
                )
            }

            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 8.dp, vertical = 2.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {

                IconButton(onClick = onPrevious, enabled = !stopped, modifier = Modifier.size(40.dp)) {
                    Icon(
                        painter = painterResource(android.R.drawable.ic_media_previous),
                        contentDescription = stringResource(R.string.cd_previous),
                        modifier = Modifier.size(22.dp)
                    )
                }

                IconButton(onClick = onTogglePlayPause, enabled = !stopped, modifier = Modifier.size(44.dp)) {
                    Icon(
                        painter = painterResource(
                            if (playback.isPlaying) android.R.drawable.ic_media_pause
                            else android.R.drawable.ic_media_play
                        ),
                        contentDescription = stringResource(if (playback.isPlaying) R.string.cd_pause else R.string.cd_play),
                        modifier = Modifier.size(24.dp)
                    )
                }

                IconButton(onClick = onNext, enabled = !stopped, modifier = Modifier.size(40.dp)) {
                    Icon(
                        painter = painterResource(android.R.drawable.ic_media_next),
                        contentDescription = stringResource(R.string.cd_next),
                        modifier = Modifier.size(22.dp)
                    )
                }

                Spacer(Modifier.width(8.dp))

                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = recording?.artist ?: "",
                        style = MaterialTheme.typography.labelSmall,
                        color = Color(0xFF25B300),
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                    Text(
                        text = recording?.title ?: "",
                        style = MaterialTheme.typography.bodyMedium,
                        fontWeight = FontWeight.Medium,
                        maxLines = 1,
                        modifier = Modifier.basicMarquee(
                            iterations = Int.MAX_VALUE,
                            repeatDelayMillis = 2000,
                            initialDelayMillis = 3000,
                            velocity = 30.dp
                        )
                    )
                }

                Spacer(Modifier.width(8.dp))

                IconButton(onClick = onStop, enabled = !stopped, modifier = Modifier.size(40.dp)) {
                    Icon(
                        imageVector = Icons.Default.Stop,
                        contentDescription = stringResource(R.string.cd_stop),
                        modifier = Modifier.size(22.dp)
                    )
                }
            }
        }
    }
}

/** Milliseconds to "m:ss". Negative/unknown durations render as 0:00. */
private fun formatTime(ms: Long): String {
    val totalSeconds = (ms.coerceAtLeast(0L) / 1000L).toInt()
    val minutes = totalSeconds / 60
    val seconds = totalSeconds % 60
    return "%d:%02d".format(minutes, seconds)
}
