package com.pixelized.biblib.ui.composable.animation

import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp


@Composable
fun AnimatedDelayerScope.AnimatedOffset(
    modifier: Modifier = Modifier,
    transitionLabel: String = "AnimatedOffset",
    contentAlignment: Alignment = Alignment.TopStart,
    content: @Composable BoxScope.() -> Unit,
) {
    AnimatedOffset(
        modifier = modifier,
        transitionLabel = transitionLabel,
        delay = play(),
        contentAlignment = contentAlignment,
        content = content,
    )
}

@Composable
fun AnimatedOffset(
    modifier: Modifier = Modifier,
    transitionLabel: String = "AnimatedOffset",
    delay: Delay = Delay(),
    contentAlignment: Alignment = Alignment.TopStart,
    content: @Composable BoxScope.() -> Unit,
) {
    val displayed = rememberSavableMutableTransitionState(
        initialState = LocalInspectionMode.current,
        targetState = true,
    )
    AnimatedOffset(
        modifier = modifier,
        transitionLabel = transitionLabel,
        displayed = displayed,
        delay = delay,
        contentAlignment = contentAlignment,
        content = content,
    )
}

@Composable
fun AnimatedOffset(
    modifier: Modifier = Modifier,
    displayed: MutableTransitionState<Boolean>,
    transitionLabel: String = "AnimatedOffset",
    delay: Delay = Delay(),
    contentAlignment: Alignment = Alignment.TopStart,
    content: @Composable BoxScope.() -> Unit,
) {
    val transition: TransitionData = updateTransition(
        displayed = displayed,
        label = transitionLabel,
        delay = delay.value,
    )
    Box(
        modifier = modifier
            .offset(y = transition.offset)
            .graphicsLayer(alpha = transition.alpha, clip = false),
        contentAlignment = contentAlignment,
        content = content
    )
}

//////////////////////////////////////
// region: Transition

private class TransitionData(
    alpha: State<Float>,
    offset: State<Dp>,
) {
    val alpha by alpha
    val offset by offset
}

@Composable
private fun updateTransition(
    displayed: MutableTransitionState<Boolean>,
    label: String,
    duration: Int = 600,
    delay: Int = 0,
    easing: CubicBezierEasing = CubicBezierEasing(0.25f, 1f, 0.5f, 1f),
    fromAlpha: Float = 0f,
    toAlpha: Float = 1f,
    fromOffset: Dp = 64.dp,
    toOffset: Dp = 0.dp,
): TransitionData {
    val transition = updateTransition(transitionState = displayed, label = label)
    val alpha = transition.animateFloat(
        label = "$label :: alpha",
        transitionSpec = { tween(durationMillis = duration, easing = easing, delayMillis = delay) },
    ) {
        when (it) {
            true -> toAlpha
            else -> fromAlpha
        }
    }
    val offset = transition.animateDp(
        label = "$label :: offset",
        transitionSpec = { tween(durationMillis = duration, easing = easing, delayMillis = delay) },
    ) {
        when (it) {
            true -> toOffset
            else -> fromOffset
        }
    }
    return remember(transition) { TransitionData(alpha, offset) }
}

// endregion