package ru.forbion.f7cloud.core.designsystem

import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.pointerInput

interface F7OverlayNavigationScope {
    fun registerDismissHandler(handler: () -> Boolean): () -> Unit

    fun dismissTopOverlay(): Boolean
}

private class F7OverlayNavigationScopeImpl : F7OverlayNavigationScope {
    private val handlers = mutableStateListOf<() -> Boolean>()

    override fun registerDismissHandler(handler: () -> Boolean): () -> Unit {
        handlers.add(handler)
        return { handlers.remove(handler) }
    }

    override fun dismissTopOverlay(): Boolean {
        for (index in handlers.indices.reversed()) {
            if (handlers[index]()) {
                return true
            }
        }
        return false
    }
}

val LocalF7OverlayNavigation = compositionLocalOf<F7OverlayNavigationScope?> { null }

@Composable
fun F7OverlayNavigationProvider(
    onSwipeDismiss: () -> Boolean,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    val scope = remember { F7OverlayNavigationScopeImpl() }
    CompositionLocalProvider(LocalF7OverlayNavigation provides scope) {
        androidx.compose.foundation.layout.Box(
            modifier = modifier.f7SwipeFromRightToDismiss {
                if (scope.dismissTopOverlay()) return@f7SwipeFromRightToDismiss
                onSwipeDismiss()
            },
        ) {
            content()
        }
    }
}

@Composable
fun F7OverlayDismissHandler(
    enabled: Boolean,
    onDismiss: () -> Unit,
) {
    val scope = LocalF7OverlayNavigation.current ?: return
    DisposableEffect(enabled, scope, onDismiss) {
        if (!enabled) {
            return@DisposableEffect onDispose {}
        }
        val unregister = scope.registerDismissHandler {
            onDismiss()
            true
        }
        onDispose(unregister)
    }
}

fun Modifier.f7SwipeFromRightToDismiss(
    enabled: Boolean = true,
    edgeFraction: Float = 0.24f,
    dismissDistanceFraction: Float = 0.14f,
    onDismiss: () -> Unit,
): Modifier {
    if (!enabled) return this
    return pointerInput(Unit) {
        val edgeStartPx = size.width * (1f - edgeFraction)
        val dismissDistancePx = size.width * dismissDistanceFraction
        awaitEachGesture {
            val down = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial)
            if (down.position.x < edgeStartPx) return@awaitEachGesture

            var dragLeft = 0f
            while (true) {
                val event = awaitPointerEvent(pass = PointerEventPass.Initial)
                val change = event.changes.firstOrNull { it.id == down.id } ?: break
                if (!change.pressed) break
                val delta = change.position.x - change.previousPosition.x
                if (delta < 0f) {
                    dragLeft += -delta
                }
                if (dragLeft >= dismissDistancePx) {
                    onDismiss()
                    break
                }
            }
        }
    }
}
