package com.ponzischeme89.memby.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.border
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.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
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.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.tv.material3.Button
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.ponzischeme89.memby.data.EmbyRepository
import com.ponzischeme89.memby.data.model.MyShow
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import com.ponzischeme89.memby.ui.theme.MembySurfaceRaised

@Composable
internal fun MyShowsStrip(
    shows: List<MyShow>,
    repository: EmbyRepository,
    availableWidth: Dp,
    density: String,
    navigationFocusRequester: FocusRequester,
    contentFocusRequester: FocusRequester?,
    onShowSelected: (MyShow) -> Unit,
    onContentFocused: () -> Unit,
) {
    Column(
        modifier = Modifier.fillMaxWidth(),
        verticalArrangement = Arrangement.spacedBy(HomeRowHeaderSpacing),
    ) {
        Row(
            modifier = Modifier.fillMaxWidth().padding(horizontal = 36.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            HomeRowHeaderIcon(Icons.Default.Bookmark)
            Spacer(Modifier.width(HomeRowHeaderIconGap))
            Text(
                "My Shows",
                color = Color(0xFFF1F3F4),
                fontSize = 20.sp,
                fontWeight = FontWeight.Bold,
            )
            if (shows.isNotEmpty()) {
                Text(
                    shows.size.toString(),
                    color = Color(0xFFAEB7BF),
                    fontSize = 12.sp,
                    fontWeight = FontWeight.SemiBold,
                    modifier = Modifier
                        .padding(start = 10.dp)
                        .clip(RoundedCornerShape(20.dp))
                        .background(Color.White.copy(alpha = 0.08f))
                        .padding(horizontal = 8.dp, vertical = 3.dp),
                )
            }
        }
        if (shows.isEmpty()) {
            Text(
                "Open any series and choose “Add to My Shows”.",
                color = Color(0xFFAEB7BF),
                fontSize = 14.sp,
                modifier = Modifier.padding(horizontal = 36.dp, vertical = 18.dp),
            )
        } else {
            val cardsAcross = when (density) {
                "compact" -> 8
                "large" -> 5
                else -> 7
            }
            val cardWidth = responsiveRowCardWidth(availableWidth, cardsAcross, 102.dp, 218.dp)
            LazyRow(
                contentPadding = PaddingValues(horizontal = 36.dp, vertical = 10.dp),
                horizontalArrangement = Arrangement.spacedBy(16.dp),
            ) {
                items(shows, key = MyShow::itemId) { show ->
                    MyShowCard(
                        show = show,
                        repository = repository,
                        width = cardWidth,
                        onClick = { onShowSelected(show) },
                        modifier = Modifier
                            .then(
                                if (show.itemId == shows.first().itemId && contentFocusRequester != null) {
                                    Modifier.focusRequester(contentFocusRequester)
                                } else {
                                    Modifier
                                },
                            )
                            .focusProperties { left = navigationFocusRequester }
                            .onFocusChanged { if (it.hasFocus) onContentFocused() },
                    )
                }
            }
        }
    }
}

@Composable
private fun MyShowCard(
    show: MyShow,
    repository: EmbyRepository,
    width: Dp,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    FocusScaleContainer(
        onFocused = {},
        onClick = onClick,
        contentDescription = "${show.title}, ${myShowCardSubtitle(show)}",
        modifier = modifier.width(width),
    ) { focused ->
        Column {
            Box(
                modifier = Modifier
                    .width(width)
                    .aspectRatio(2f / 3f)
                    .shadow(if (focused) 7.dp else 0.dp, RoundedCornerShape(9.dp))
                    .clip(RoundedCornerShape(9.dp))
                    .background(MembySurfaceRaised)
                    .border(
                        2.dp,
                        if (focused) Color.White else Color.White.copy(alpha = 0.07f),
                        RoundedCornerShape(9.dp),
                    ),
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = repository.myShowImageUrl(show.itemId, show.imageTag),
                    contentDescription = null,
                    contentScale = ContentScale.Fit,
                    modifier = Modifier.fillMaxSize(),
                )
                myShowBadge(show)?.let { (status, label) ->
                    LifecycleBadge(
                        status = status,
                        label = label,
                        modifier = Modifier.align(Alignment.TopStart).padding(8.dp),
                    )
                }
            }
            Text(
                show.title,
                color = if (focused) Color.White else Color(0xFFE1E5E8),
                fontSize = 14.sp,
                fontWeight = if (focused) FontWeight.Bold else FontWeight.SemiBold,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
                modifier = Modifier.padding(top = 7.dp).fillMaxWidth(),
            )
            Text(
                myShowCardSubtitle(show),
                color = Color(0xFFAEB7BF),
                fontSize = 12.sp,
                fontWeight = FontWeight.Medium,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
                modifier = Modifier.padding(top = 2.dp).fillMaxWidth(),
            )
        }
    }
}

/**
 * The tag a followed show wears, as a `status to label` pair for [LifecycleBadge] — the same
 * vocabulary and therefore the same colours as the Sonarr and Radarr schedule rows, so one
 * word means one thing wherever it appears on the launcher.
 *
 * The order is the priority. A cancelled show wins outright: nothing else on the card
 * matters as much as "there will be no more of this", which is why it is the one tag drawn
 * in red. Sonarr not monitoring it comes next, then a dated next episode, which is more
 * useful than the general fact that the show continues.
 */
internal fun myShowBadge(show: MyShow): Pair<String, String>? = when {
    show.lifecycle == "Cancelled" -> "ended" to "CANCELLED"
    show.sonarrStatus == "Not monitored" -> "unmonitored" to "UNMONITORED"
    !show.nextEpisode.isNullOrBlank() -> "upcoming" to "UPCOMING"
    show.lifecycle == "Continuing" -> "continuing" to "CONTINUING"
    else -> null
}

internal fun myShowCardSubtitle(show: MyShow): String {
    if (!show.nextEpisode.isNullOrBlank()) {
        val date = runCatching {
            DateTimeFormatter.ofPattern("EEE, d MMM")
                .format(Instant.parse(show.nextEpisode).atZone(ZoneId.systemDefault()))
        }.getOrNull()
        if (date != null) return "Next episode · $date"
    }
    return when {
        show.lifecycle != "Unknown" -> show.lifecycle
        show.sonarrStatus != "Not found" -> show.sonarrStatus
        else -> "Saved show"
    }
}

@Composable
internal fun MyShowDetailsOverlay(
    show: MyShow,
    repository: EmbyRepository,
    removing: Boolean,
    onRemove: () -> Unit,
    onClose: () -> Unit,
) {
    Box(
        Modifier.fillMaxSize().zIndex(8f).background(Color(0xF5090B0D)),
        contentAlignment = Alignment.Center,
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth(0.72f)
                .background(Color(0xFF151A1E), RoundedCornerShape(20.dp))
                .padding(34.dp),
            horizontalArrangement = Arrangement.spacedBy(30.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            AsyncImage(
                model = repository.myShowImageUrl(show.itemId, show.imageTag, 500),
                contentDescription = null,
                contentScale = ContentScale.Fit,
                modifier = Modifier
                    .width(170.dp)
                    .aspectRatio(2f / 3f)
                    .clip(RoundedCornerShape(12.dp))
                    .background(MembySurfaceRaised)
                    .border(1.dp, Color.White.copy(alpha = 0.12f), RoundedCornerShape(12.dp)),
            )
            Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(10.dp)) {
                Text(show.title, color = Color.White, fontSize = 30.sp, fontWeight = FontWeight.Bold)
                StatusLine("Sonarr", show.sonarrStatus)
                StatusLine("Next episode", formatMyShowDate(show.nextEpisode))
                StatusLine("Series status", show.lifecycle)
                Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
                    Button(onClick = onRemove, enabled = !removing) {
                        Text(if (removing) "Removing…" else "Remove from My Shows")
                    }
                    Button(onClick = onClose) { Text("Close") }
                }
            }
        }
    }
}

@Composable
private fun StatusLine(label: String, value: String) {
    Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
        Text("$label:", color = Color(0xFFAEB7BF), fontSize = 16.sp)
        Text(value, color = Color.White, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
    }
}

internal fun formatMyShowDate(value: String?): String {
    if (value.isNullOrBlank()) return "Not announced"
    return runCatching {
        DateTimeFormatter.ofPattern("EEE, d MMM yyyy · h:mm a")
            .format(Instant.parse(value).atZone(ZoneId.systemDefault()))
    }.getOrDefault("Not announced")
}
