package cy.hexor.furumi.ui.player

import android.content.Intent
import android.graphics.Bitmap
import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import cy.hexor.furumi.domain.model.ArtistCard
import cy.hexor.furumi.domain.model.ConnectedDevice
import cy.hexor.furumi.domain.model.ConnectedDevicesState
import cy.hexor.furumi.domain.model.ConnectedJam
import cy.hexor.furumi.domain.model.ConnectedJamUser
import cy.hexor.furumi.domain.model.PlaylistCard
import cy.hexor.furumi.domain.model.ReleaseCard
import cy.hexor.furumi.domain.model.TrackCard
import cy.hexor.furumi.domain.model.ListeningHistoryItem
import cy.hexor.furumi.playback.AudioPlaybackState
import cy.hexor.furumi.ui.theme.FurumiBlack
import cy.hexor.furumi.ui.theme.FurumiElectricCyan
import cy.hexor.furumi.ui.theme.FurumiHotOrange
import cy.hexor.furumi.ui.theme.FurumiLine
import cy.hexor.furumi.ui.theme.FurumiNeonPink
import cy.hexor.furumi.ui.theme.FurumiNeonViolet
import cy.hexor.furumi.ui.theme.FurumiSurface
import cy.hexor.furumi.ui.theme.FurumiSurfaceHigh
import cy.hexor.furumi.ui.theme.FurumiTextMuted
import kotlin.math.roundToInt

@Composable
internal fun FullPlayerOverlay(
    playback: AudioPlaybackState,
    coverBitmap: Bitmap?,
    mediaImages: Map<String, Bitmap>,
    likedTrackIds: Set<Long>,
    onMediaImageNeeded: (String?) -> Unit,
    dragOffsetY: Float,
    onDragOffsetChange: (Float) -> Unit,
    onDismiss: () -> Unit,
    onPlayPause: () -> Unit,
    onPrevious: () -> Unit,
    onNext: () -> Unit,
    onToggleShuffle: () -> Unit,
    onCycleRepeatMode: () -> Unit,
    onSeekToProgress: (Float) -> Unit,
    onQueueTrackClick: (TrackCard, Int) -> Unit,
    onToggleLike: (Long) -> Unit,
    onPlayNext: (TrackCard) -> Unit,
    onPlayLast: (TrackCard) -> Unit,
    onShare: (TrackCard) -> Unit,
    onAddToPlaylist: (TrackCard) -> Unit,
    onArtistClick: (cy.hexor.furumi.domain.model.ArtistCard) -> Unit,
    connectedDevicesState: ConnectedDevicesState?,
    connectedDevicesError: String?,
    onDeviceClick: (String) -> Unit,
    onCreateJam: () -> Unit,
    onJoinJam: (String) -> Unit,
    onLeaveJam: (String) -> Unit,
    jamInviteQuery: String,
    jamInviteUsers: List<ConnectedJamUser>,
    isJamInviteSearchLoading: Boolean,
    onJamInviteQueryChange: (String) -> Unit,
    onInviteToJam: (String, Long) -> Unit
) {
    val track = playback.currentTrack ?: return
    val queue = playback.queue
    var isDevicesMenuOpen by rememberSaveable { mutableStateOf(false) }
    var currentTrackMenuExpanded by remember { mutableStateOf(false) }
    var showPreviousQueue by remember { mutableStateOf(false) }

    BackHandler(enabled = isDevicesMenuOpen) {
        isDevicesMenuOpen = false
    }

    LaunchedEffect(track.coverUrl) {
        onMediaImageNeeded(track.coverUrl)
    }

    val density = LocalDensity.current
    val dismissThresholdPx = with(density) { 150.dp.toPx() }
    val flingVelocityThresholdPx = with(density) { 800.dp.toPx() }
    val scrollState = rememberScrollState()
    val currentOnDismiss by androidx.compose.runtime.rememberUpdatedState(onDismiss)

    val nestedScrollConnection = remember(dragOffsetY) {
        object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection {
            override fun onPreScroll(
                available: androidx.compose.ui.geometry.Offset,
                source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
            ): androidx.compose.ui.geometry.Offset {
                val dy = available.y
                if (dy < 0 && dragOffsetY > 0f) {
                    val consumed = dy.coerceAtLeast(-dragOffsetY)
                    onDragOffsetChange((dragOffsetY + consumed).coerceAtLeast(0f))
                    return androidx.compose.ui.geometry.Offset(0f, consumed)
                }
                return androidx.compose.ui.geometry.Offset.Zero
            }

            override fun onPostScroll(
                consumed: androidx.compose.ui.geometry.Offset,
                available: androidx.compose.ui.geometry.Offset,
                source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
            ): androidx.compose.ui.geometry.Offset {
                val dy = available.y
                // Only allow drag-to-dismiss when content is scrolled to top
                // and user is actively dragging (not fling inertia from scrolling up)
                if (dy > 0 && scrollState.value == 0
                    && source == androidx.compose.ui.input.nestedscroll.NestedScrollSource.Drag) {
                    onDragOffsetChange(dragOffsetY + dy)
                    return androidx.compose.ui.geometry.Offset(0f, dy)
                }
                return androidx.compose.ui.geometry.Offset.Zero
            }

            override suspend fun onPreFling(
                available: androidx.compose.ui.unit.Velocity
            ): androidx.compose.ui.unit.Velocity {
                // Only consider dismiss if we actually have a drag offset
                if (dragOffsetY <= 0f) {
                    return androidx.compose.ui.unit.Velocity.Zero
                }
                val shouldDismiss = dragOffsetY > dismissThresholdPx ||
                        available.y > flingVelocityThresholdPx
                if (shouldDismiss) {
                    onDragOffsetChange(0f)
                    currentOnDismiss()
                    return available
                }
                val anim = Animatable(dragOffsetY)
                anim.animateTo(0f) { onDragOffsetChange(value) }
                onDragOffsetChange(0f)
                return androidx.compose.ui.unit.Velocity.Zero
            }

            override suspend fun onPostFling(
                consumed: androidx.compose.ui.unit.Velocity,
                available: androidx.compose.ui.unit.Velocity
            ): androidx.compose.ui.unit.Velocity {
                if (dragOffsetY > 0f) {
                    val shouldDismiss = dragOffsetY > dismissThresholdPx ||
                            available.y > flingVelocityThresholdPx
                    if (shouldDismiss) {
                        onDragOffsetChange(0f)
                        currentOnDismiss()
                    } else {
                        val anim = Animatable(dragOffsetY)
                        anim.animateTo(0f) { onDragOffsetChange(value) }
                        onDragOffsetChange(0f)
                    }
                }
                return available
            }
        }
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .offset { IntOffset(0, dragOffsetY.roundToInt().coerceAtLeast(0)) }
            .nestedScroll(nestedScrollConnection)
            .background(MaterialTheme.colorScheme.background)
            .windowInsetsPadding(WindowInsets.safeDrawing)
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(scrollState)
                .padding(horizontal = 24.dp, vertical = 18.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                Text(
                    text = "Now playing",
                    style = MaterialTheme.typography.labelLarge,
                    color = FurumiTextMuted
                )
                Row(verticalAlignment = Alignment.CenterVertically) {
                    RoundControlButton(
                        size = 42,
                        background = FurumiSurface,
                        onClick = { onShare(track) }
                    ) {
                        ShareGlyph(
                            modifier = Modifier.size(20.dp),
                            color = MaterialTheme.colorScheme.onBackground
                        )
                    }
                    Spacer(modifier = Modifier.width(12.dp))
                    Box {
                        RoundControlButton(
                            size = 42,
                            background = FurumiSurface,
                            onClick = { currentTrackMenuExpanded = true }
                        ) {
                            MoreDotsGlyph(
                                modifier = Modifier.size(22.dp),
                                color = MaterialTheme.colorScheme.onBackground
                            )
                        }
                        TrackContextMenu(
                            expanded = currentTrackMenuExpanded,
                            isLiked = likedTrackIds.contains(track.id),
                            onDismiss = { currentTrackMenuExpanded = false },
                            onToggleLike = {
                                currentTrackMenuExpanded = false
                                onToggleLike(track.id)
                            },
                            onPlayNext = {
                                currentTrackMenuExpanded = false
                                onPlayNext(track)
                            },
                            onPlayLast = {
                                currentTrackMenuExpanded = false
                                onPlayLast(track)
                            },
                            onShare = {
                                currentTrackMenuExpanded = false
                                onShare(track)
                            },
                            onAddToPlaylist = {
                                currentTrackMenuExpanded = false
                                onAddToPlaylist(track)
                            }
                        )
                    }
                    Spacer(modifier = Modifier.width(12.dp))
                    RoundControlButton(
                        size = 42,
                        background = if (connectedDevicesState?.currentJamId != null) FurumiNeonPink else FurumiSurface,
                        onClick = { isDevicesMenuOpen = true }
                    ) {
                        DevicesGlyph(
                            modifier = Modifier.size(22.dp),
                            color = if (connectedDevicesState?.currentJamId != null) FurumiBlack else MaterialTheme.colorScheme.onBackground
                        )
                    }
                }
            }

            Spacer(modifier = Modifier.height(36.dp))

            MediaArtwork(
                title = track.title,
                seedId = track.id,
                bitmap = coverBitmap,
                modifier = Modifier
                    .fillMaxWidth()
                    .aspectRatio(1f),
                cornerRadius = 12
            )

            Spacer(modifier = Modifier.height(28.dp))

            Text(
                text = track.title,
                style = MaterialTheme.typography.headlineMedium,
                color = MaterialTheme.colorScheme.onBackground,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis
            )
            
            val artists = track.artistRefs.ifEmpty { 
                track.artists.mapIndexed { i, name -> cy.hexor.furumi.domain.model.ArtistRef(id = -(i + 1L), name = name) } 
            }
            
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically
            ) {
                artists.forEachIndexed { index, artistRef ->
                    Text(
                        text = artistRef.name,
                        style = MaterialTheme.typography.bodyLarge,
                        color = if (artistRef.id > 0) FurumiNeonPink else FurumiTextMuted,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                        modifier = Modifier.clickable(enabled = artistRef.id > 0) {
                            onArtistClick(
                                cy.hexor.furumi.domain.model.ArtistCard(
                                    id = artistRef.id,
                                    name = artistRef.name,
                                    imageUrl = null,
                                    releaseCount = 0,
                                    trackCount = 0
                                )
                            )
                        }
                    )
                    if (index < artists.lastIndex) {
                        Text(
                            text = ", ",
                            style = MaterialTheme.typography.bodyLarge,
                            color = FurumiTextMuted
                        )
                    }
                }
                
                if (playback.errorMessage != null) {
                    Text(
                        text = " • ${playback.errorMessage}",
                        style = MaterialTheme.typography.bodyLarge,
                        color = FurumiHotOrange,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                }
            }

            Spacer(modifier = Modifier.height(26.dp))

            PlayerProgress(
                playback = playback,
                onSeekToProgress = onSeekToProgress
            )

            Spacer(modifier = Modifier.height(24.dp))

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly,
                verticalAlignment = Alignment.CenterVertically
            ) {
                RoundControlButton(
                    size = 48,
                    background = FurumiSurface,
                    onClick = onToggleShuffle
                ) {
                    ShuffleGlyph(
                        modifier = Modifier.size(20.dp),
                        color = if (playback.shuffle) FurumiNeonPink else MaterialTheme.colorScheme.onBackground
                    )
                }
                RoundControlButton(
                    size = 48,
                    background = FurumiSurface,
                    onClick = onPrevious
                ) {
                    PreviousGlyph(Modifier.size(20.dp), MaterialTheme.colorScheme.onBackground)
                }
                RoundControlButton(
                    size = 72,
                    background = FurumiNeonPink,
                    onClick = onPlayPause
                ) {
                    PlaybackGlyph(
                        playback = playback,
                        playSize = 24,
                        pauseSize = 24
                    )
                }
                RoundControlButton(
                    size = 48,
                    background = FurumiSurface,
                    onClick = onNext
                ) {
                    NextGlyph(Modifier.size(20.dp), MaterialTheme.colorScheme.onBackground)
                }
                RoundControlButton(
                    size = 48,
                    background = FurumiSurface,
                    onClick = onCycleRepeatMode
                ) {
                    RepeatGlyph(
                        modifier = Modifier.size(22.dp),
                        color = if (playback.repeatMode.equals("off", ignoreCase = true)) {
                            MaterialTheme.colorScheme.onBackground
                        } else {
                            FurumiNeonPink
                        },
                        repeatMode = playback.repeatMode
                    )
                }
            }

            Spacer(modifier = Modifier.height(34.dp))

            SectionTitle("Queue")
            Spacer(modifier = Modifier.height(12.dp))
            FullPlayerQueue(
                queue = queue,
                playback = playback,
                mediaImages = mediaImages,
                likedTrackIds = likedTrackIds,
                showPreviousQueue = showPreviousQueue,
                onShowPrevious = { showPreviousQueue = true },
                onMediaImageNeeded = onMediaImageNeeded,
                onQueueTrackClick = onQueueTrackClick,
                onToggleLike = onToggleLike,
                onPlayNext = onPlayNext,
                onPlayLast = onPlayLast,
                onShare = onShare,
                onAddToPlaylist = onAddToPlaylist
            )
        }

        if (isDevicesMenuOpen) {
            DevicesJamMenu(
                connectedDevicesState = connectedDevicesState,
                connectedDevicesError = connectedDevicesError,
                onDismiss = { isDevicesMenuOpen = false },
                onDeviceClick = onDeviceClick,
                onCreateJam = onCreateJam,
                onJoinJam = onJoinJam,
                onLeaveJam = onLeaveJam,
                jamInviteQuery = jamInviteQuery,
                jamInviteUsers = jamInviteUsers,
                isJamInviteSearchLoading = isJamInviteSearchLoading,
                onJamInviteQueryChange = onJamInviteQueryChange,
                onInviteToJam = onInviteToJam
            )
        }
    }
}

@Composable
private fun FullPlayerQueue(
    queue: List<TrackCard>,
    playback: AudioPlaybackState,
    mediaImages: Map<String, Bitmap>,
    likedTrackIds: Set<Long>,
    showPreviousQueue: Boolean,
    onShowPrevious: () -> Unit,
    onMediaImageNeeded: (String?) -> Unit,
    onQueueTrackClick: (TrackCard, Int) -> Unit,
    onToggleLike: (Long) -> Unit,
    onPlayNext: (TrackCard) -> Unit,
    onPlayLast: (TrackCard) -> Unit,
    onShare: (TrackCard) -> Unit,
    onAddToPlaylist: (TrackCard) -> Unit
) {
    if (queue.isEmpty()) {
        Text(
            text = "Queue is empty",
            style = MaterialTheme.typography.bodyMedium,
            color = FurumiTextMuted
        )
        return
    }

    val currentIndex = playback.currentIndex
        .takeIf { it in queue.indices }
        ?: queue.indexOfFirst { it.id == playback.currentTrack?.id }
            .takeIf { it >= 0 }
        ?: 0
    val firstVisibleIndex = if (showPreviousQueue) 0 else currentIndex
    val visibleQueue = queue
        .mapIndexed { index, queueTrack -> index to queueTrack }
        .drop(firstVisibleIndex)

    if (!showPreviousQueue && currentIndex > 0) {
        Box(
            modifier = Modifier.fillMaxWidth(),
            contentAlignment = Alignment.Center
        ) {
            Surface(
                modifier = Modifier
                    .height(30.dp)
                    .clip(CircleShape)
                    .clickable(onClick = onShowPrevious),
                shape = CircleShape,
                color = FurumiSurface,
                border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
            ) {
                Box(
                    modifier = Modifier.padding(horizontal = 14.dp),
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = "Show previous",
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.onBackground
                    )
                }
            }
        }
        Spacer(modifier = Modifier.height(12.dp))
    }

    visibleQueue.forEachIndexed { visibleIndex, (index, queueTrack) ->
        val isPlayed = index < currentIndex
        val isCurrent = index == currentIndex

        QueueTrackRow(
            track = queueTrack,
            bitmap = mediaImageFor(mediaImages, queueTrack.coverUrl),
            isLiked = likedTrackIds.contains(queueTrack.id),
            isPlayed = isPlayed,
            isCurrent = isCurrent,
            onMediaImageNeeded = onMediaImageNeeded,
            onClick = { onQueueTrackClick(queueTrack, index) },
            onToggleLike = { onToggleLike(queueTrack.id) },
            onPlayNext = { onPlayNext(queueTrack) },
            onPlayLast = { onPlayLast(queueTrack) },
            onShare = { onShare(queueTrack) },
            onAddToPlaylist = { onAddToPlaylist(queueTrack) }
        )
        if (visibleIndex < visibleQueue.lastIndex) {
            Spacer(modifier = Modifier.height(12.dp))
        }
    }
}

@Composable
internal fun PlayerProgress(
    playback: AudioPlaybackState,
    onSeekToProgress: (Float) -> Unit
) {
    Column {
        Slider(
            value = playback.progress,
            onValueChange = onSeekToProgress,
            enabled = playback.durationMs > 0L,
            colors = SliderDefaults.colors(
                thumbColor = FurumiNeonPink,
                activeTrackColor = FurumiNeonPink,
                inactiveTrackColor = FurumiLine,
                disabledThumbColor = FurumiTextMuted,
                disabledActiveTrackColor = FurumiLine,
                disabledInactiveTrackColor = FurumiLine
            )
        )
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(
                text = formatPlaybackTime(playback.positionMs),
                style = MaterialTheme.typography.labelSmall,
                color = FurumiTextMuted
            )
            Text(
                text = formatPlaybackTime(playback.durationMs),
                style = MaterialTheme.typography.labelSmall,
                color = FurumiTextMuted
            )
        }
    }
}

@Composable
private fun DevicesJamMenu(
    connectedDevicesState: ConnectedDevicesState?,
    connectedDevicesError: String?,
    onDismiss: () -> Unit,
    onDeviceClick: (String) -> Unit,
    onCreateJam: () -> Unit,
    onJoinJam: (String) -> Unit,
    onLeaveJam: (String) -> Unit,
    jamInviteQuery: String,
    jamInviteUsers: List<ConnectedJamUser>,
    isJamInviteSearchLoading: Boolean,
    onJamInviteQueryChange: (String) -> Unit,
    onInviteToJam: (String, Long) -> Unit
) {
    Surface(
        modifier = Modifier
            .fillMaxSize()
            .clickable(onClick = onDismiss),
        color = Color.Black.copy(alpha = 0.54f)
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.BottomCenter
        ) {
            Surface(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight(0.78f)
                    .clickable(enabled = false, onClick = {}),
                shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp),
                color = FurumiSurfaceHigh,
                border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
            ) {
                Column(
                    modifier = Modifier
                        .fillMaxSize()
                        .verticalScroll(rememberScrollState())
                        .padding(horizontal = 20.dp, vertical = 18.dp)
                ) {
                    Box(
                        modifier = Modifier
                            .width(42.dp)
                            .height(4.dp)
                            .clip(CircleShape)
                            .background(FurumiLine)
                            .align(Alignment.CenterHorizontally)
                    )
                    Spacer(modifier = Modifier.height(18.dp))
                    Text(
                        text = "Connect to a device",
                        style = MaterialTheme.typography.titleMedium,
                        color = MaterialTheme.colorScheme.onBackground
                    )
                    Spacer(modifier = Modifier.height(4.dp))
                    Text(
                        text = "Choose where Furumi plays.",
                        style = MaterialTheme.typography.bodyMedium,
                        color = FurumiTextMuted
                    )

                    connectedDevicesError?.let { error ->
                        Spacer(modifier = Modifier.height(14.dp))
                        Text(
                            text = error,
                            style = MaterialTheme.typography.bodyMedium,
                            color = FurumiHotOrange,
                            maxLines = 2,
                            overflow = TextOverflow.Ellipsis
                        )
                    }

                    Spacer(modifier = Modifier.height(18.dp))
                    DevicesMenuSection(
                        devices = connectedDevicesState?.devices.orEmpty(),
                        onDeviceClick = onDeviceClick
                    )
                    Spacer(modifier = Modifier.height(24.dp))
                    JamMenuSection(
                        connectedDevicesState = connectedDevicesState,
                        onCreateJam = onCreateJam,
                        onJoinJam = onJoinJam,
                        onLeaveJam = onLeaveJam,
                        jamInviteQuery = jamInviteQuery,
                        jamInviteUsers = jamInviteUsers,
                        isJamInviteSearchLoading = isJamInviteSearchLoading,
                        onJamInviteQueryChange = onJamInviteQueryChange,
                        onInviteToJam = onInviteToJam
                    )
                    Spacer(modifier = Modifier.height(12.dp))
                }
            }
        }
    }
}

@Composable
private fun DevicesMenuSection(
    devices: List<ConnectedDevice>,
    onDeviceClick: (String) -> Unit
) {
    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
        SectionTitle("Devices")
        if (devices.isEmpty()) {
            Text(
                text = "Looking for devices...",
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
        } else {
            devices.forEach { device ->
                DeviceMenuRow(
                    device = device,
                    onClick = { onDeviceClick(device.id) }
                )
            }
        }
    }
}

@Composable
private fun DeviceMenuRow(
    device: ConnectedDevice,
    onClick: () -> Unit
) {
    Surface(
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(8.dp))
            .clickable(onClick = onClick),
        shape = RoundedCornerShape(8.dp),
        color = if (device.isActive) FurumiSurface else Color.Transparent,
        border = if (device.isActive) androidx.compose.foundation.BorderStroke(1.dp, FurumiNeonPink) else null
    ) {
        Row(
            modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Box(
                modifier = Modifier
                    .size(10.dp)
                    .clip(CircleShape)
                    .background(if (device.isActive) FurumiNeonPink else FurumiLine)
            )
            Spacer(modifier = Modifier.width(14.dp))
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = device.name,
                    style = MaterialTheme.typography.labelLarge,
                    color = if (device.isActive) MaterialTheme.colorScheme.onBackground else FurumiTextMuted,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                if (device.isCurrent || device.isActive) {
                    Text(
                        text = if (device.isCurrent) "Current device" else "Playing",
                        style = MaterialTheme.typography.bodySmall,
                        color = if (device.isActive) FurumiNeonPink else FurumiTextMuted,
                        maxLines = 1
                    )
                }
            }
            if (device.isActive) {
                DevicesGlyph(
                    modifier = Modifier.size(20.dp),
                    color = FurumiNeonPink
                )
            }
        }
    }
}

@Composable
private fun JamMenuSection(
    connectedDevicesState: ConnectedDevicesState?,
    onCreateJam: () -> Unit,
    onJoinJam: (String) -> Unit,
    onLeaveJam: (String) -> Unit,
    jamInviteQuery: String,
    jamInviteUsers: List<ConnectedJamUser>,
    isJamInviteSearchLoading: Boolean,
    onJamInviteQueryChange: (String) -> Unit,
    onInviteToJam: (String, Long) -> Unit
) {
    val jams = connectedDevicesState?.jams.orEmpty()
    val currentJam = jams.firstOrNull { it.id == connectedDevicesState?.currentJamId }
        ?: jams.firstOrNull { it.isActive }
    val invitedJams = jams.filter { it.isPending && !it.isMember }
    val joinedJam = currentJam ?: jams.firstOrNull { it.isMember }

    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
        SectionTitle("Jam")
        if (joinedJam != null) {
            JamCard(
                jam = joinedJam,
                onJoin = { onJoinJam(joinedJam.id) },
                onLeave = { onLeaveJam(joinedJam.id) },
                inviteQuery = jamInviteQuery,
                inviteUsers = jamInviteUsers,
                isInviteSearchLoading = isJamInviteSearchLoading,
                onInviteQueryChange = onJamInviteQueryChange,
                onInvite = { userId -> onInviteToJam(joinedJam.id, userId) }
            )
        } else {
            JamStartCard(onCreateJam = onCreateJam)
        }

        invitedJams.forEach { jam ->
            JamInviteRow(
                jam = jam,
                onJoin = { onJoinJam(jam.id) }
            )
        }
    }
}

@Composable
private fun JamCard(
    jam: ConnectedJam,
    onJoin: () -> Unit,
    onLeave: () -> Unit,
    inviteQuery: String,
    inviteUsers: List<ConnectedJamUser>,
    isInviteSearchLoading: Boolean,
    onInviteQueryChange: (String) -> Unit,
    onInvite: (Long) -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(10.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(12.dp)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Box(
                    modifier = Modifier
                        .size(32.dp)
                        .clip(CircleShape)
                        .background(FurumiNeonViolet.copy(alpha = 0.2f)),
                    contentAlignment = Alignment.Center
                ) {
                    Text("J", color = FurumiNeonViolet, fontWeight = FontWeight.Bold)
                }
                Spacer(modifier = Modifier.width(12.dp))
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = jam.name,
                        style = MaterialTheme.typography.labelLarge,
                        color = MaterialTheme.colorScheme.onBackground,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                    Text(
                        text = "${jam.memberCount} listeners",
                        style = MaterialTheme.typography.bodySmall,
                        color = FurumiTextMuted
                    )
                }
                PillAction(
                    label = if (jam.isOwner) "End" else "Leave",
                    selected = false,
                    modifier = Modifier.height(32.dp).width(74.dp),
                    onClick = onLeave
                )
            }
            
            if (jam.isMember) {
                Spacer(modifier = Modifier.height(14.dp))
                JamInviteSearch(
                    query = inviteQuery,
                    users = inviteUsers,
                    isLoading = isInviteSearchLoading,
                    onQueryChange = onInviteQueryChange,
                    onInvite = onInvite
                )
            } else {
                Spacer(modifier = Modifier.height(12.dp))
                PillAction(
                    label = "Join Jam",
                    selected = true,
                    modifier = Modifier.fillMaxWidth().height(40.dp),
                    onClick = onJoin
                )
            }
        }
    }
}

@Composable
private fun JamStartCard(
    onCreateJam: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Row(
            modifier = Modifier.padding(14.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = "Start a Jam",
                    style = MaterialTheme.typography.labelLarge,
                    color = MaterialTheme.colorScheme.onBackground
                )
                Text(
                    text = "Listen together from this device.",
                    style = MaterialTheme.typography.bodyMedium,
                    color = FurumiTextMuted
                )
            }
            Spacer(modifier = Modifier.width(12.dp))
            PillAction(
                label = "Start",
                selected = true,
                modifier = Modifier.width(96.dp),
                onClick = onCreateJam
            )
        }
    }
}

@Composable
private fun JamInviteSearch(
    query: String,
    users: List<ConnectedJamUser>,
    isLoading: Boolean,
    onQueryChange: (String) -> Unit,
    onInvite: (Long) -> Unit
) {
    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
        Text(
            text = "Invite people",
            style = MaterialTheme.typography.labelLarge,
            color = MaterialTheme.colorScheme.onBackground
        )
        TextField(
            value = query,
            onValueChange = onQueryChange,
            modifier = Modifier
                .fillMaxWidth()
                .height(54.dp),
            shape = RoundedCornerShape(8.dp),
            singleLine = true,
            placeholder = {
                Text(
                    text = "Search user",
                    style = MaterialTheme.typography.bodyLarge
                )
            },
            leadingIcon = {
                SearchGlyph(
                    modifier = Modifier.size(20.dp),
                    color = FurumiBlack
                )
            }
        )
        when {
            isLoading -> {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(42.dp),
                    contentAlignment = Alignment.Center
                ) {
                    CircularProgressIndicator(
                        modifier = Modifier.size(20.dp),
                        color = FurumiNeonPink,
                        strokeWidth = 2.dp
                    )
                }
            }
            query.isNotBlank() && users.isEmpty() -> {
                Text(
                    text = "No users found",
                    style = MaterialTheme.typography.bodyMedium,
                    color = FurumiTextMuted
                )
            }
            else -> users.forEach { user ->
                JamInviteUserRow(
                    user = user,
                    onInvite = { onInvite(user.id) }
                )
            }
        }
    }
}

@Composable
private fun JamInviteUserRow(
    user: ConnectedJamUser,
    onInvite: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(10.dp),
        color = FurumiBlack.copy(alpha = 0.20f),
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Row(
            modifier = Modifier.padding(12.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = user.displayLabel,
                    style = MaterialTheme.typography.labelLarge,
                    color = MaterialTheme.colorScheme.onBackground,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                Text(
                    text = user.email?.takeIf { it.isNotBlank() } ?: "@${user.username}",
                    style = MaterialTheme.typography.bodyMedium,
                    color = FurumiTextMuted,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
            }
            Spacer(modifier = Modifier.width(12.dp))
            PillAction(
                label = "Invite",
                selected = true,
                modifier = Modifier.width(96.dp),
                onClick = onInvite
            )
        }
    }
}

@Composable
private fun JamInviteRow(
    jam: ConnectedJam,
    onJoin: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(10.dp),
        color = FurumiBlack.copy(alpha = 0.20f),
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Row(
            modifier = Modifier.padding(12.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = jam.name,
                    style = MaterialTheme.typography.labelLarge,
                    color = MaterialTheme.colorScheme.onBackground,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                Text(
                    text = "Invitation from ${jam.hostName}",
                    style = MaterialTheme.typography.bodyMedium,
                    color = FurumiTextMuted,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
            }
            Spacer(modifier = Modifier.width(12.dp))
            PillAction(
                label = "Join",
                selected = true,
                modifier = Modifier.width(92.dp),
                onClick = onJoin
            )
        }
    }
}

@Composable
internal fun RoundControlButton(
    size: Int,
    background: Color,
    onClick: () -> Unit,
    content: @Composable BoxScope.() -> Unit
) {
    Box(
        modifier = Modifier
            .size(size.dp)
            .clip(CircleShape)
            .background(background)
            .clickable(onClick = onClick),
        contentAlignment = Alignment.Center,
        content = content
    )
}
