package com.fabledsword.minstrel.connectivity.ui

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
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.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.composables.icons.lucide.CloudOff
import com.composables.icons.lucide.Lucide
import com.fabledsword.minstrel.connectivity.NetworkStatusController
import com.fabledsword.minstrel.connectivity.ServerHealth
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject

private const val BACK_ONLINE_FLASH_MS = 2_000L

/**
 * Exposes [NetworkStatusController]'s tri-state directly to the banner. No
 * re-wrapping StateFlow — the controller's is already app-scoped and warm.
 */
@HiltViewModel
class ConnectivityBannerViewModel @Inject constructor(
    networkStatus: NetworkStatusController,
    @Suppress("UnusedPrivateProperty") savedStateHandle: SavedStateHandle,
) : ViewModel() {
    val health: StateFlow<ServerHealth> = networkStatus.state
}

/**
 * Shell banner. Tells the user *why* they're degraded — no link vs server-down
 * — plus a non-alarming "Reconnecting…" for the transient [ServerHealth.Unstable]
 * window, and a brief "Back online" confirmation when health recovers so
 * recovery is unmistakable. Sentence case, understated voice (design system).
 */
@Composable
fun ConnectionErrorBanner(
    viewModel: ConnectivityBannerViewModel = hiltViewModel(),
) {
    val health by viewModel.health.collectAsStateWithLifecycle()
    var showBackOnline by remember { mutableStateOf(false) }
    var wasDown by remember { mutableStateOf(false) }

    LaunchedEffect(health) {
        val down = health == ServerHealth.Offline || health == ServerHealth.ServerDown
        if (health == ServerHealth.Healthy && wasDown) {
            // try/finally so a mid-delay cancellation (health flips again) can't
            // orphan the flag and leave "Back online" stuck on screen.
            try {
                showBackOnline = true
                delay(BACK_ONLINE_FLASH_MS)
            } finally {
                showBackOnline = false
            }
        }
        wasDown = down
    }

    AnimatedVisibility(
        visible = health != ServerHealth.Healthy || showBackOnline,
        enter = expandVertically() + fadeIn(),
        exit = shrinkVertically() + fadeOut(),
    ) {
        BannerContent(health = health, backOnline = showBackOnline)
    }
}

@Composable
private fun BannerContent(health: ServerHealth, backOnline: Boolean) {
    val scheme = MaterialTheme.colorScheme
    val background: Color
    val foreground: Color
    when {
        backOnline -> {
            background = scheme.secondaryContainer
            foreground = scheme.onSecondaryContainer
        }
        health == ServerHealth.Unstable -> {
            background = scheme.surfaceVariant
            foreground = scheme.onSurfaceVariant
        }
        else -> {
            background = scheme.errorContainer
            foreground = scheme.onErrorContainer
        }
    }
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .background(background)
            .padding(horizontal = 16.dp, vertical = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        Icon(imageVector = Lucide.CloudOff, contentDescription = null, tint = foreground)
        Text(
            text = bannerText(health, backOnline),
            style = MaterialTheme.typography.bodyMedium,
            color = foreground,
        )
    }
}

private fun bannerText(health: ServerHealth, backOnline: Boolean): String = when {
    backOnline -> "Back online."
    health == ServerHealth.Offline -> "No connection — check Wi-Fi or mobile data."
    health == ServerHealth.ServerDown ->
        "Server unreachable — your cached content is still available."
    health == ServerHealth.Unstable -> "Reconnecting…"
    else -> ""
}
