package app.closer.ui.messages

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
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.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
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.draw.clip
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.hilt.navigation.compose.hiltViewModel
import app.closer.core.navigation.AppRoute
import app.closer.ui.messages.components.ChatComposer
import app.closer.ui.messages.components.ChatDaySeparator
import app.closer.ui.messages.components.ChatMessageRow
import app.closer.ui.messages.components.isSameChatDay
import app.closer.ui.theme.closerBackgroundBrush
import coil.compose.AsyncImage

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConversationScreen(
    onNavigate: (String) -> Unit = {},
    viewModel: ConversationViewModel = hiltViewModel()
) {
    val state by viewModel.uiState.collectAsState()
    val listState = rememberLazyListState()
    val snackbarHostState = remember { SnackbarHostState() }

    val routeToPaywall: () -> Unit = {
        viewModel.onMediaPaywallShown()
        onNavigate(AppRoute.PAYWALL)
    }

    // Surface send failures as a snackbar.
    LaunchedEffect(Unit) {
        viewModel.events.collect { snackbarHostState.showSnackbar(it) }
    }

    // Scroll to the bottom on first load and when a NEW message arrives while near the bottom —
    // never when older history is prepended (that would yank the reader away).
    var prevLastId by remember { mutableStateOf<String?>(null) }
    val lastId = state.messages.lastOrNull()?.id
    LaunchedEffect(lastId) {
        if (lastId == null) return@LaunchedEffect
        val lastIndex = state.messages.lastIndex
        val lastVisible = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
        if (prevLastId == null || lastVisible >= lastIndex - 2) {
            listState.animateScrollToItem(lastIndex)
        }
        prevLastId = lastId
    }

    // Load older messages when the user scrolls to the very top.
    val atTop by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 } }
    LaunchedEffect(atTop, state.canLoadMore) {
        if (atTop && state.canLoadMore) viewModel.loadOlderMessages()
    }

    Scaffold(
        containerColor = Color.Transparent,
        modifier = Modifier.background(closerBackgroundBrush()),
        snackbarHost = { SnackbarHost(snackbarHostState) },
        topBar = {
            TopAppBar(
                title = {
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        ConversationAvatar(state.partnerPhotoUrl)
                        Text(
                            text = state.title,
                            fontWeight = FontWeight.SemiBold,
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis,
                            modifier = Modifier.padding(start = 10.dp),
                            color = MaterialTheme.colorScheme.onSurface
                        )
                    }
                },
                navigationIcon = {
                    IconButton(onClick = { onNavigate("back") }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
            )
        }
    ) { padding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(padding)
                .imePadding()
                .navigationBarsPadding()
        ) {
            LazyColumn(
                state = listState,
                modifier = Modifier.weight(1f),
                contentPadding = PaddingValues(horizontal = 14.dp, vertical = 8.dp),
                verticalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                val lastOwnIndex = state.messages.indexOfLast { it.userId == viewModel.currentUserId }
                itemsIndexed(state.messages, key = { _, m -> m.id }) { index, message ->
                    val isMe = message.userId == viewModel.currentUserId
                    val isLastInRun = index == state.messages.lastIndex ||
                        state.messages[index + 1].userId != message.userId
                    val prev = state.messages.getOrNull(index - 1)
                    if (prev == null || !isSameChatDay(prev.createdAt, message.createdAt)) {
                        ChatDaySeparator(message.createdAt)
                    }
                    val seen = isMe && index == lastOwnIndex &&
                        message.createdAt > 0 && state.partnerReadAt >= message.createdAt
                    ChatMessageRow(
                        message = message,
                        isCurrentUser = isMe,
                        partnerAvatarUrl = state.partnerPhotoUrl,
                        showAvatar = isLastInRun,
                        showTimestamp = isLastInRun,
                        showSeen = seen,
                        canReact = state.canSendMedia,
                        onReact = { emoji -> viewModel.react(message.id, emoji) },
                        onReactBlocked = routeToPaywall,
                        onDelete = { viewModel.deleteMessage(message.id) },
                        loadDecryptedMedia = viewModel::loadDecryptedMedia
                    )
                }
            }

            if (state.partnerTyping) {
                Text(
                    text = "typing…",
                    style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
                    modifier = Modifier.padding(start = 20.dp, bottom = 2.dp)
                )
            }

            state.pendingMedia.forEach { pm ->
                PendingMediaChip(
                    pending = pm,
                    onRetry = { viewModel.retryMedia(pm.id) },
                    onDismiss = { viewModel.dismissPending(pm.id) }
                )
            }

            ChatComposer(
                value = state.messageInput,
                onValueChange = viewModel::updateMessageInput,
                onSend = viewModel::sendMessage,
                onSendImage = viewModel::sendImage,
                onSendVoice = viewModel::sendVoice,
                canSendMedia = state.canSendMedia,
                onUpgrade = routeToPaywall,
                modifier = Modifier.padding(horizontal = 8.dp, vertical = 6.dp)
            )
        }
    }
}

@Composable
private fun PendingMediaChip(
    pending: PendingMedia,
    onRetry: () -> Unit,
    onDismiss: () -> Unit
) {
    val label = if (pending.type == "voice") "voice note" else "photo"
    Surface(
        shape = RoundedCornerShape(20.dp),
        color = MaterialTheme.colorScheme.surfaceVariant,
        modifier = Modifier.padding(horizontal = 14.dp, vertical = 2.dp)
    ) {
        Row(
            modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            if (pending.failed) {
                Text(
                    text = "Couldn't send $label",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )
                IconButton(onClick = onRetry, modifier = Modifier.size(28.dp)) {
                    Icon(Icons.Filled.Refresh, contentDescription = "Retry", tint = MaterialTheme.colorScheme.primary)
                }
                IconButton(onClick = onDismiss, modifier = Modifier.size(28.dp)) {
                    Icon(Icons.Filled.Close, contentDescription = "Dismiss", tint = MaterialTheme.colorScheme.onSurfaceVariant)
                }
            } else {
                CircularProgressIndicator(
                    strokeWidth = 2.dp,
                    modifier = Modifier.size(16.dp),
                    color = MaterialTheme.colorScheme.primary
                )
                Text(
                    text = "Sending $label…",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }
        }
    }
}

@Composable
private fun ConversationAvatar(url: String?) {
    val size = 32.dp
    if (!url.isNullOrBlank()) {
        AsyncImage(
            model = url,
            contentDescription = null,
            contentScale = ContentScale.Crop,
            modifier = Modifier.size(size).clip(CircleShape)
        )
    } else {
        Icon(
            imageVector = Icons.Filled.Person,
            contentDescription = null,
            tint = MaterialTheme.colorScheme.onSurfaceVariant,
            modifier = Modifier.size(size).clip(CircleShape)
        )
    }
}
