@file:Suppress("TooManyFunctions")
// SearchScreen legitimately owns the screen-shell composable + a handful
// of small section/row helpers (ResultsPane, ResultsList, three section
// builders, two row variants, hint, loader). Splitting into a widgets/
// subdirectory for a single screen would be over-engineering.

package com.fabledsword.minstrel.search.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import com.composables.icons.lucide.ArrowLeft
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.X
import com.fabledsword.minstrel.library.widgets.AlbumCard
import com.fabledsword.minstrel.library.widgets.ArtistCard
import com.fabledsword.minstrel.models.AlbumRef
import com.fabledsword.minstrel.models.ArtistRef
import com.fabledsword.minstrel.models.SearchResponseRef
import com.fabledsword.minstrel.models.TrackRef
import com.fabledsword.minstrel.nav.AlbumDetail
import com.fabledsword.minstrel.nav.ArtistDetail
import com.fabledsword.minstrel.nav.Search as SearchRoute
import com.fabledsword.minstrel.shared.widgets.ShellContentWindowInsets
import com.fabledsword.minstrel.shared.widgets.TrackRow
import com.fabledsword.minstrel.shared.widgets.ErrorRetry
import com.fabledsword.minstrel.shared.widgets.LoadingCentered
import com.fabledsword.minstrel.shared.widgets.MainAppBarActions
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchScreen(
    navController: NavHostController,
    viewModel: SearchViewModel = hiltViewModel(),
    playerViewModel: com.fabledsword.minstrel.player.ui.PlayerViewModel = hiltViewModel(),
) {
    val state by viewModel.state.collectAsStateWithLifecycle()
    val playerState by playerViewModel.uiState.collectAsStateWithLifecycle()
    val playingTrackId = playerState.currentTrack?.id
    val focusRequester = remember { FocusRequester() }
    LaunchedEffect(Unit) { focusRequester.requestFocus() }

    Scaffold(
        contentWindowInsets = ShellContentWindowInsets,
        modifier = Modifier.fillMaxSize(),
        topBar = {
            TopAppBar(
                title = {
                    SearchField(
                        query = state.query,
                        onQueryChange = viewModel::setQuery,
                        focusRequester = focusRequester,
                    )
                },
                navigationIcon = {
                    IconButton(onClick = { navController.popBackStack() }) {
                        Icon(Lucide.ArrowLeft, contentDescription = "Back")
                    }
                },
                actions = {
                    if (state.query.isNotEmpty()) {
                        IconButton(onClick = { viewModel.clear() }) {
                            Icon(Lucide.X, contentDescription = "Clear")
                        }
                    }
                    MainAppBarActions(
                        navController = navController,
                        currentRouteName = SearchRoute::class.qualifiedName,
                    )
                },
            )
        },
    ) { inner ->
        Box(modifier = Modifier.fillMaxSize().padding(inner)) {
            ResultsPane(
                state = state.results,
                playingTrackId = playingTrackId,
                onArtistClick = { id -> navController.navigate(ArtistDetail(id)) },
                onAlbumClick = { id -> navController.navigate(AlbumDetail(id)) },
                onTrackPlay = viewModel::playTrack,
                onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
                onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
                onRetry = viewModel::retry,
            )
        }
    }
}

@Composable
private fun SearchField(
    query: String,
    onQueryChange: (String) -> Unit,
    focusRequester: FocusRequester,
) {
    TextField(
        value = query,
        onValueChange = onQueryChange,
        modifier = Modifier
            .fillMaxWidth()
            .focusRequester(focusRequester),
        placeholder = { Text("Search artists, albums, tracks") },
        singleLine = true,
        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
        colors = TextFieldDefaults.colors(
            focusedContainerColor = Color.Transparent,
            unfocusedContainerColor = Color.Transparent,
            focusedIndicatorColor = Color.Transparent,
            unfocusedIndicatorColor = Color.Transparent,
        ),
    )
}

@Composable
private fun ResultsPane(
    state: SearchResultsState,
    playingTrackId: String?,
    onArtistClick: (String) -> Unit,
    onAlbumClick: (String) -> Unit,
    onTrackPlay: (TrackRef) -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
    onRetry: () -> Unit,
) {
    when (state) {
        SearchResultsState.Idle -> CenteredHint("Type to search your library.")
        SearchResultsState.Loading -> LoadingCentered()
        is SearchResultsState.Error -> ErrorRetry(
            title = "Search failed",
            message = state.message,
            onRetry = onRetry,
        )
        is SearchResultsState.Loaded -> {
            if (state.response.isEmpty) {
                CenteredHint(
                    if (state.localOnly) {
                        "No matches in your on-device library."
                    } else {
                        "No matches for that query."
                    },
                )
            } else {
                Column(modifier = Modifier.fillMaxSize()) {
                    if (state.localOnly) {
                        OfflineResultsHint()
                    }
                    ResultsList(
                        response = state.response,
                        playingTrackId = playingTrackId,
                        onArtistClick = onArtistClick,
                        onAlbumClick = onAlbumClick,
                        onTrackPlay = onTrackPlay,
                        onNavigateToAlbum = onNavigateToAlbum,
                        onNavigateToArtist = onNavigateToArtist,
                    )
                }
            }
        }
    }
}

@Composable
private fun ResultsList(
    response: SearchResponseRef,
    playingTrackId: String?,
    onArtistClick: (String) -> Unit,
    onAlbumClick: (String) -> Unit,
    onTrackPlay: (TrackRef) -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(vertical = 8.dp),
    ) {
        artistsSection(response.artists, onArtistClick)
        albumsSection(response.albums, onAlbumClick)
        tracksSection(
            response.tracks,
            playingTrackId,
            onTrackPlay,
            onNavigateToAlbum,
            onNavigateToArtist,
        )
    }
}

private fun LazyListScope.artistsSection(
    artists: List<ArtistRef>,
    onArtistClick: (String) -> Unit,
) {
    if (artists.isEmpty()) return
    item { SectionHeader("Artists", artists.size) }
    item {
        LazyRow(
            contentPadding = PaddingValues(horizontal = 8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            items(items = artists, key = { "art-${it.id}" }) { artist ->
                ArtistCard(artist = artist, onClick = { onArtistClick(artist.id) })
            }
        }
    }
}

private fun LazyListScope.albumsSection(
    albums: List<AlbumRef>,
    onAlbumClick: (String) -> Unit,
) {
    if (albums.isEmpty()) return
    item { SectionHeader("Albums", albums.size) }
    item {
        LazyRow(
            contentPadding = PaddingValues(horizontal = 8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            items(items = albums, key = { "alb-${it.id}" }) { album ->
                AlbumCard(album = album, onClick = { onAlbumClick(album.id) })
            }
        }
    }
}

private fun LazyListScope.tracksSection(
    tracks: List<TrackRef>,
    playingTrackId: String?,
    onTrackPlay: (TrackRef) -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    if (tracks.isEmpty()) return
    item { SectionHeader("Tracks", tracks.size) }
    items(items = tracks, key = { "trk-${it.id}" }) { track ->
        TrackResultRow(
            track = track,
            nowPlaying = track.id == playingTrackId,
            onClick = { onTrackPlay(track) },
            onNavigateToAlbum = onNavigateToAlbum,
            onNavigateToArtist = onNavigateToArtist,
        )
        HorizontalDivider()
    }
}

@Composable
private fun TrackResultRow(
    track: TrackRef,
    nowPlaying: Boolean,
    onClick: () -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    TrackRow(
        title = track.title,
        artist = track.artistName.ifEmpty { track.albumTitle },
        trackId = track.id,
        onClick = onClick,
        nowPlaying = nowPlaying,
        enabled = track.streamUrl.isNotEmpty(),
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        leading = {
            TrackCoverThumb(coverUrl = track.coverUrl, contentDescription = track.title)
        },
        trailing = {
            TrackActionsButton(
                track = track,
                onNavigateToAlbum = onNavigateToAlbum,
                onNavigateToArtist = onNavigateToArtist,
            )
        },
    )
}

@Composable
private fun SectionHeader(label: String, count: Int) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        Text(
            text = label,
            style = MaterialTheme.typography.titleMedium,
            color = MaterialTheme.colorScheme.onBackground,
        )
        Text(
            text = "$count",
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

@Composable
private fun OfflineResultsHint() {
    Text(
        text = "Showing on-device matches only — the server is unreachable.",
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 6.dp),
        style = MaterialTheme.typography.bodySmall,
        color = MaterialTheme.colorScheme.onSurfaceVariant,
    )
}

@Composable
private fun CenteredHint(text: String) {
    Box(modifier = Modifier.fillMaxSize().padding(24.dp), contentAlignment = Alignment.Center) {
        Text(
            text = text,
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

