package com.rosetta.messenger.ui.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.UnfoldMore
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
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.graphics.Path
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.rosetta.messenger.R
import kotlinx.coroutines.delay
import kotlin.math.roundToInt

private fun Float.isFiniteValue(): Boolean = !isNaN() && !isInfinite()

@Composable
fun SharedMediaFastScrollOverlay(
    visible: Boolean,
    progress: Float,
    monthLabel: String,
    isDarkTheme: Boolean,
    showHint: Boolean,
    onHintDismissed: () -> Unit,
    onDragProgressChanged: (Float) -> Unit,
    modifier: Modifier = Modifier
) {
    if (!visible) return

    val density = androidx.compose.ui.platform.LocalDensity.current
    val handleSize = 48.dp
    val handleSizePx = with(density) { handleSize.toPx() }
    val bubbleOffsetX = with(density) { (-96).dp.roundToPx() }

    var rootHeightPx by remember { mutableIntStateOf(0) }
    var trackHeightPx by remember { mutableIntStateOf(0) }
    var monthBubbleHeightPx by remember { mutableIntStateOf(0) }
    var isDragging by remember { mutableStateOf(false) }
    val initialProgress = if (progress.isFiniteValue()) progress.coerceIn(0f, 1f) else 0f
    var dragProgress by remember { mutableFloatStateOf(initialProgress) }
    var hintVisible by remember(showHint) { mutableStateOf(showHint) }

    val normalizedProgress = if (progress.isFiniteValue()) progress.coerceIn(0f, 1f) else 0f

    LaunchedEffect(showHint) {
        if (showHint) {
            hintVisible = true
            delay(4000)
            hintVisible = false
            onHintDismissed()
        } else {
            hintVisible = false
        }
    }

    LaunchedEffect(normalizedProgress, isDragging) {
        if (!isDragging) {
            dragProgress = normalizedProgress
        }
    }

    val shownProgressRaw = if (isDragging) dragProgress else normalizedProgress
    val shownProgress =
        if (shownProgressRaw.isFiniteValue()) shownProgressRaw.coerceIn(0f, 1f) else 0f
    val rawTrackTravel = (trackHeightPx - handleSizePx)
    val trackTravelPx =
        if (rawTrackTravel.isFiniteValue()) rawTrackTravel.coerceAtLeast(1f) else 1f
    val rawHandleOffsetYPx = trackTravelPx * shownProgress
    val handleOffsetYPx =
        if (rawHandleOffsetYPx.isFiniteValue()) rawHandleOffsetYPx.coerceIn(0f, trackTravelPx)
        else 0f
    val latestShownProgress by rememberUpdatedState(shownProgress)
    val latestHandleOffsetYPx by rememberUpdatedState(handleOffsetYPx)
    val handleCenterYPx = handleOffsetYPx + handleSizePx / 2f
    val trackTopPx = ((rootHeightPx - trackHeightPx) / 2f).coerceAtLeast(0f)
    val bubbleYValue = trackTopPx + handleCenterYPx - monthBubbleHeightPx / 2f
    val bubbleY = if (bubbleYValue.isFiniteValue()) bubbleYValue.roundToInt() else 0

    Box(
        modifier = modifier
            .fillMaxSize()
            .onSizeChanged { rootHeightPx = it.height }
    ) {
        AnimatedVisibility(
            visible = hintVisible && !isDragging,
            enter = fadeIn(),
            exit = fadeOut(),
            modifier = Modifier
                .align(Alignment.CenterEnd)
                .padding(end = 60.dp)
        ) {
            SharedMediaFastScrollHint(isDarkTheme = isDarkTheme)
        }

        Box(
            modifier = Modifier
                .align(Alignment.CenterEnd)
                .padding(end = 2.dp)
                .fillMaxHeight(0.86f)
                .width(56.dp)
                .onSizeChanged { trackHeightPx = it.height }
                .pointerInput(trackTravelPx, handleSizePx) {
                    if (trackTravelPx <= 0f) return@pointerInput
                    var dragFromHandle = false
                    detectDragGestures(
                        onDragStart = { offset ->
                            val handleLeft = size.width - handleSizePx
                            val handleRight = size.width.toFloat()
                            val handleTop = latestHandleOffsetYPx
                            val handleBottom = handleTop + handleSizePx
                            dragFromHandle =
                                offset.x in handleLeft..handleRight &&
                                    offset.y in handleTop..handleBottom
                            if (!dragFromHandle) return@detectDragGestures

                            isDragging = true
                            dragProgress = latestShownProgress
                            if (hintVisible) {
                                hintVisible = false
                                onHintDismissed()
                            }
                        },
                        onDragEnd = {
                            if (dragFromHandle) {
                                isDragging = false
                            }
                            dragFromHandle = false
                        },
                        onDragCancel = {
                            if (dragFromHandle) {
                                isDragging = false
                            }
                            dragFromHandle = false
                        },
                        onDrag = { change, dragAmount ->
                            if (!dragFromHandle) return@detectDragGestures
                            change.consume()
                            val nextProgress =
                                (dragProgress + dragAmount.y / trackTravelPx).coerceIn(0f, 1f)
                            if (nextProgress != dragProgress) {
                                dragProgress = nextProgress
                                onDragProgressChanged(nextProgress)
                            }
                        }
                    )
                }
        ) {
            TelegramDateHandle(
                isDarkTheme = isDarkTheme,
                modifier = Modifier
                    .align(Alignment.TopEnd)
                    .offset {
                        val safeHandleOffset =
                            if (handleOffsetYPx.isFiniteValue()) handleOffsetYPx.roundToInt()
                            else 0
                        IntOffset(0, safeHandleOffset)
                    }
                    .size(handleSize)
            )
        }

        AnimatedVisibility(
            visible = isDragging && monthLabel.isNotBlank(),
            enter = fadeIn(),
            exit = fadeOut(),
            modifier = Modifier
                .align(Alignment.TopEnd)
                .offset { IntOffset(bubbleOffsetX, bubbleY) }
        ) {
            SharedMediaMonthBubble(
                monthLabel = monthLabel,
                isDarkTheme = isDarkTheme,
                onMeasured = { monthBubbleHeightPx = it }
            )
        }
    }
}

@Composable
private fun TelegramDateHandle(isDarkTheme: Boolean, modifier: Modifier = Modifier) {
    val handleBackground = if (isDarkTheme) Color(0xFF3D4C63) else Color(0xFFEAF0F8)
    val borderColor = if (isDarkTheme) Color(0x668EA0BA) else Color(0x33405673)
    val arrowColor = if (isDarkTheme) Color(0xFFF0F4FB) else Color(0xFF4A5A73)

    Box(
        modifier = modifier
            .shadow(8.dp, CircleShape, clip = false)
            .clip(CircleShape)
            .background(handleBackground)
            .border(1.dp, borderColor, CircleShape)
    ) {
        androidx.compose.foundation.Canvas(modifier = Modifier.fillMaxSize()) {
            drawTelegramArrowPair(color = arrowColor)
        }
    }
}

private fun DrawScope.drawTelegramArrowPair(color: Color) {
    val centerX = size.width / 2f
    val centerY = size.height / 2f
    val halfWidth = size.minDimension * 0.12f
    val halfHeight = size.minDimension * 0.08f
    val gap = size.minDimension * 0.14f

    val up = Path().apply {
        moveTo(centerX - halfWidth, centerY - gap + halfHeight)
        lineTo(centerX + halfWidth, centerY - gap + halfHeight)
        lineTo(centerX, centerY - gap - halfHeight)
        close()
    }
    val down = Path().apply {
        moveTo(centerX - halfWidth, centerY + gap - halfHeight)
        lineTo(centerX + halfWidth, centerY + gap - halfHeight)
        lineTo(centerX, centerY + gap + halfHeight)
        close()
    }
    drawPath(path = up, color = color)
    drawPath(path = down, color = color)
}

@Composable
private fun SharedMediaMonthBubble(
    monthLabel: String,
    isDarkTheme: Boolean,
    onMeasured: (Int) -> Unit
) {
    val bubbleBackground = if (isDarkTheme) Color(0xFF3C4655) else Color(0xFFF1F5FB)
    val bubbleBorder = if (isDarkTheme) Color(0x55424F62) else Color(0x223D4D66)
    val textColor = if (isDarkTheme) Color(0xFFF2F5FB) else Color(0xFF283548)

    Text(
        text = monthLabel,
        color = textColor,
        maxLines = 1,
        overflow = TextOverflow.Clip,
        style = TextStyle(
            fontSize = 14.sp,
            fontWeight = FontWeight.SemiBold
        ),
        modifier = Modifier
            .onSizeChanged { onMeasured(it.height) }
            .clip(RoundedCornerShape(18.dp))
            .background(bubbleBackground)
            .border(1.dp, bubbleBorder, RoundedCornerShape(18.dp))
            .padding(horizontal = 12.dp, vertical = 6.dp)
            .widthIn(min = 94.dp)
    )
}

@Composable
private fun SharedMediaFastScrollHint(isDarkTheme: Boolean) {
    val background = if (isDarkTheme) Color(0xEA2A323D) else Color(0xEA26374E)
    val iconBackground = if (isDarkTheme) Color(0x553C4656) else Color(0x55324A67)

    Row(
        modifier = Modifier
            .clip(RoundedCornerShape(8.dp))
            .background(background)
            .padding(horizontal = 10.dp, vertical = 8.dp)
            .widthIn(max = 300.dp)
            .heightIn(min = 34.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Box(
            modifier = Modifier
                .size(20.dp)
                .clip(RoundedCornerShape(5.dp))
                .background(iconBackground),
            contentAlignment = Alignment.Center
        ) {
            Icon(
                imageVector = Icons.Default.UnfoldMore,
                contentDescription = null,
                tint = Color.White.copy(alpha = 0.92f),
                modifier = Modifier.size(12.dp)
            )
        }
        Text(
            text = stringResource(R.string.shared_media_fast_scroll_hint),
            color = Color.White.copy(alpha = 0.92f),
            fontSize = 13.sp,
            lineHeight = 16.sp
        )
    }
}
