package app.closer.ui.components

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Chat
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
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.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import app.closer.notifications.MessageBubbleController
import app.closer.ui.theme.CloserPalette
import coil.compose.AsyncImage
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.math.roundToInt

@HiltViewModel
class MessageBubbleViewModel @Inject constructor(
    private val controller: MessageBubbleController
) : ViewModel() {
    val bubble = controller.bubble
    fun dismiss() = controller.dismiss()
}

/**
 * A Messenger-style draggable chat-head shown over the app's own UI when a partner message
 * arrives in a conversation that isn't currently open. Drag to move (snaps to the nearest edge),
 * tap to open the thread, auto-dismisses after a while.
 */
@Composable
fun MessageBubbleOverlay(
    onOpen: (coupleId: String, conversationId: String) -> Unit,
    viewModel: MessageBubbleViewModel = hiltViewModel()
) {
    val bubble by viewModel.bubble.collectAsState()
    val current = bubble ?: return

    val density = LocalDensity.current
    val bubbleSize = 60.dp
    val margin = 14.dp

    BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
        val maxXpx = with(density) { maxWidth.toPx() }
        val maxYpx = with(density) { maxHeight.toPx() }
        val sizePx = with(density) { bubbleSize.toPx() }
        val marginPx = with(density) { margin.toPx() }
        val rightEdge = (maxXpx - sizePx - marginPx).coerceAtLeast(0f)

        // Reset position to the right edge each time a new bubble appears.
        var offsetX by remember(current.conversationId) { mutableFloatStateOf(rightEdge) }
        var offsetY by remember(current.conversationId) { mutableFloatStateOf(maxYpx * 0.32f) }

        // The bubble persists until the message is read — opening the conversation clears it (via
        // ActiveThreadMonitor) — or the user flicks it down onto the dismiss target. No timeout.
        var dragging by remember(current.conversationId) { mutableStateOf(false) }
        var nearDismiss by remember(current.conversationId) { mutableStateOf(false) }
        val dismissZonePx = with(density) { 150.dp.toPx() }

        // Drag-to-dismiss target at the bottom-center, shown only while dragging.
        if (dragging) {
            Box(
                modifier = Modifier
                    .align(Alignment.BottomCenter)
                    .padding(bottom = 48.dp)
                    .size(if (nearDismiss) 66.dp else 54.dp)
                    .shadow(6.dp, CircleShape)
                    .clip(CircleShape)
                    .background(
                        if (nearDismiss) CloserPalette.PinkAccentDeep else Color.Black.copy(alpha = 0.45f)
                    ),
                contentAlignment = Alignment.Center
            ) {
                Icon(
                    imageVector = Icons.Filled.Close,
                    contentDescription = "Dismiss",
                    tint = Color.White,
                    modifier = Modifier.size(28.dp)
                )
            }
        }

        Box(
            modifier = Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .size(bubbleSize)
                .shadow(10.dp, CircleShape)
                .clip(CircleShape)
                .background(CloserPalette.PurpleRich)
                .border(2.5.dp, Color.White, CircleShape)
                .pointerInput(current.conversationId) {
                    detectDragGestures(
                        onDragStart = { dragging = true },
                        onDrag = { change, drag ->
                            change.consume()
                            offsetX = (offsetX + drag.x).coerceIn(0f, rightEdge)
                            offsetY = (offsetY + drag.y).coerceIn(marginPx, maxYpx - sizePx - marginPx)
                            nearDismiss = (offsetY + sizePx) > (maxYpx - dismissZonePx)
                        },
                        onDragEnd = {
                            dragging = false
                            if (nearDismiss) {
                                viewModel.dismiss()
                            } else {
                                // Snap to whichever side is closer (chat-head behaviour).
                                offsetX = if (offsetX + sizePx / 2f < maxXpx / 2f) marginPx else rightEdge
                            }
                            nearDismiss = false
                        },
                        onDragCancel = {
                            dragging = false
                            nearDismiss = false
                        }
                    )
                }
                .pointerInput(current.conversationId) {
                    detectTapGestures(onTap = {
                        onOpen(current.coupleId, current.conversationId)
                        viewModel.dismiss()
                    })
                },
            contentAlignment = Alignment.Center
        ) {
            val avatar = current.avatarUrl
            if (!avatar.isNullOrBlank()) {
                AsyncImage(
                    model = avatar,
                    contentDescription = "Open conversation",
                    contentScale = ContentScale.Crop,
                    modifier = Modifier.size(bubbleSize).clip(CircleShape)
                )
            } else {
                Icon(
                    imageVector = Icons.AutoMirrored.Filled.Chat,
                    contentDescription = "Open conversation",
                    tint = Color.White,
                    modifier = Modifier.size(26.dp)
                )
            }

            if (current.count > 1) {
                Box(
                    modifier = Modifier
                        .align(Alignment.TopEnd)
                        .size(22.dp)
                        .clip(CircleShape)
                        .background(CloserPalette.PinkAccentDeep)
                        .border(2.dp, Color.White, CircleShape),
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = if (current.count > 9) "9+" else current.count.toString(),
                        color = Color.White,
                        style = MaterialTheme.typography.labelSmall,
                        fontWeight = FontWeight.Bold
                    )
                }
            }
        }
    }
}
