package com.fabledsword.minstrel.shared.widgets

import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.fabledsword.minstrel.connectivity.LocalServerHealth
import com.fabledsword.minstrel.connectivity.ServerHealth

private const val OFFLINE_UNAVAILABLE_ALPHA = 0.4f
private const val OFFLINE_TAP_MESSAGE = "Not downloaded — connect to play"

/**
 * Shared track-list row. Replaces the 5 per-screen `TrackRow`s — every
 * track list shares the same row skeleton (clickable Row, title + artist
 * column, CachedDot, nowPlaying highlight); only the leading element
 * (track number vs cover thumb) and the trailing controls (duration,
 * relative time, LikeButton, TrackActionsButton) vary. Callers fill
 * those via the [leading] and [trailing] slots so each screen's row is
 * a thin wrapper that no longer re-implements the Row layout.
 *
 * [enabled] gates the click (use for unavailable rows). [contentAlpha]
 * dims the title + artist text colors — pass <1f for the
 * playlist-track-unavailable case. The trailing slot is responsible
 * for applying its own alpha if it should match (the row doesn't
 * cascade because the trailing slot's content is the caller's, not
 * ours).
 *
 * Reads [LocalServerHealth] + [LocalCachedTrackIds] and intercepts taps
 * on tracks that aren't downloaded when the server is unreachable —
 * fires a Toast instead of attempting playback. The text dims so the
 * user can see at a glance which rows in a long list will work offline.
 * The trailing slot stays interactive so the kebab / like / playlist-
 * add affordances can still queue mutations for offline replay (Phase
 * 5 of #618 gates those at the action level).
 */
@Composable
fun TrackRow(
    title: String,
    artist: String,
    trackId: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    nowPlaying: Boolean = false,
    enabled: Boolean = true,
    contentAlpha: Float = 1f,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    leading: @Composable () -> Unit = {},
    trailing: @Composable RowScope.() -> Unit = {},
) {
    val context = LocalContext.current
    val health = LocalServerHealth.current
    // Unstable is non-gating — only a real gating state dims uncached rows.
    val offlineUnavailable =
        (health == ServerHealth.Offline || health == ServerHealth.ServerDown) &&
            trackId !in LocalCachedTrackIds.current
    val titleColor = if (nowPlaying) {
        MaterialTheme.colorScheme.primary
    } else {
        MaterialTheme.colorScheme.onSurface
    }
    val effectiveAlpha = if (offlineUnavailable) {
        minOf(contentAlpha, OFFLINE_UNAVAILABLE_ALPHA)
    } else {
        contentAlpha
    }
    val effectiveOnClick: () -> Unit = if (offlineUnavailable) {
        { Toast.makeText(context, OFFLINE_TAP_MESSAGE, Toast.LENGTH_SHORT).show() }
    } else {
        onClick
    }
    Row(
        modifier = modifier
            .fillMaxWidth()
            .clickable(enabled = enabled, onClick = effectiveOnClick)
            .padding(horizontal = 16.dp, vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = horizontalArrangement,
    ) {
        leading()
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = title,
                style = MaterialTheme.typography.bodyLarge,
                color = titleColor.copy(alpha = effectiveAlpha),
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
            if (artist.isNotEmpty()) {
                Text(
                    text = artist,
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = effectiveAlpha),
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
        }
        CachedDot(trackId)
        trailing()
    }
}
