package com.laseroptek.raman.utils.ext


import android.annotation.SuppressLint
import android.graphics.BlurMaskFilter
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.waitForUpOrCancellation
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.LinearGradientShader
import androidx.compose.ui.graphics.Outline
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.PaintingStyle
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.Shader
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp


/*
Row(
        modifier = Modifier.noRippleClickable {
            expanded = !expanded
        }
    ) { }
 */
inline fun Modifier.noRippleClickable(crossinline onClick: ()->Unit): Modifier = composed {
    clickable(indication = null,
        interactionSource = remember { MutableInteractionSource() }) {
        onClick()
    }
}

@Composable
fun Modifier.simpleVerticalScrollbar(
    state: LazyListState,
    width: Dp = 8.dp
): Modifier {
    val targetAlpha = if (state.isScrollInProgress) 1f else 0f
    val duration = if (state.isScrollInProgress) 150 else 500

    val alpha by animateFloatAsState(
        targetValue = targetAlpha,
        animationSpec = tween(durationMillis = duration)
    )

    return drawWithContent {
        drawContent()

        val firstVisibleElementIndex = state.layoutInfo.visibleItemsInfo.firstOrNull()?.index
        val needDrawScrollbar = state.isScrollInProgress || alpha > 0.0f

        // Draw scrollbar if scrolling or if the animation is still running and lazy column has content
        if (needDrawScrollbar && firstVisibleElementIndex != null) {
            val elementHeight = this.size.height / state.layoutInfo.totalItemsCount
            val scrollbarOffsetY = firstVisibleElementIndex * elementHeight
            val scrollbarHeight = state.layoutInfo.visibleItemsInfo.size * elementHeight

            drawRect(
                color = Color.Red,
                topLeft = Offset(this.size.width - width.toPx(), scrollbarOffsetY),
                size = Size(width.toPx(), scrollbarHeight),
                alpha = alpha
            )
        }
    }
}


fun Modifier.dropShadow(
    shape: Shape,
    color: Color = Color.Black.copy(0.25f),
    blur: Dp = 4.dp,
    offsetY: Dp = 4.dp,
    offsetX: Dp = 0.dp,
    spread: Dp = 0.dp
) = this.then(
    Modifier.drawBehind {
        val transparentColor = color.copy(alpha = 0.0f).toArgb()
        val shadowColor = color.copy(alpha = 1f).toArgb()
        this.drawIntoCanvas {
            val paint = Paint()
            val frameworkPaint = paint.asFrameworkPaint()
            frameworkPaint.color = transparentColor
            frameworkPaint.setShadowLayer(
                blur.toPx(),
                offsetX.toPx(),
                offsetY.toPx(),
                shadowColor
            )
            when (val outline = shape.createOutline(this.size, layoutDirection, this)) {
                is Outline.Rounded -> {
                    it.drawRoundRect(
                        0f,
                        0f,
                        this.size.width,
                        this.size.height,
                        outline.roundRect.topLeftCornerRadius.x,
                        outline.roundRect.bottomRightCornerRadius.y,
                        paint
                    )
                }
                else -> {
                    it.drawRect(
                        0f,
                        0f,
                        this.size.width,
                        this.size.height,
                        paint
                    )
                }
            }
        }
    }
)

fun Modifier.innerShadow(
    shape: Shape,
    color: Color,
    blur: Dp,
    offsetY: Dp,
    offsetX: Dp,
    spread: Dp
) = drawWithContent {
    drawContent()

    val rect = Rect(Offset.Zero, size)
    val paint = Paint().apply {
        this.color = color
        this.isAntiAlias = true
    }

    val shadowOutline = shape.createOutline(size, layoutDirection, this)

    drawIntoCanvas { canvas ->
        canvas.saveLayer(rect, paint)
        canvas.drawOutline(shadowOutline, paint)

        val frameworkPaint = paint.asFrameworkPaint()
        frameworkPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
        if (blur.toPx() > 0) {
            frameworkPaint.maskFilter = BlurMaskFilter(blur.toPx(), BlurMaskFilter.Blur.NORMAL)
        }
        paint.color = Color.Black

        val spreadOffsetX = offsetX.toPx() + if (offsetX.toPx() < 0) -spread.toPx() else spread.toPx()
        val spreadOffsetY = offsetY.toPx() + if (offsetY.toPx() < 0) -spread.toPx() else spread.toPx()

        canvas.translate(spreadOffsetX, spreadOffsetY)
        canvas.drawOutline(shadowOutline, paint)
        canvas.restore()
    }

}

enum class ButtonState { Pressed, Idle }
fun Modifier.bounceClick() = composed {
    val buttonState: MutableState<ButtonState> = remember { mutableStateOf(ButtonState.Idle) }
    val scale = animateFloatAsState( if(buttonState.value == ButtonState.Pressed) 0.70f else 1f)

    this
        .graphicsLayer {
            scaleX = scale.value
            scaleY = scale.value
        }
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null,
            onClick = { }
        )
        .pointerInput(buttonState) {
            awaitPointerEventScope {
                buttonState.value = if (buttonState.value == ButtonState.Pressed) {
                    waitForUpOrCancellation()
                    ButtonState.Idle
                } else {
                    awaitFirstDown(false)
                    ButtonState.Pressed
                }
            }
        }
}


fun Modifier.dashedBorder(
    width: Dp,
    radius: Dp,
    color: Color
) = drawBehind {
    drawIntoCanvas {
        val paint = Paint()
            .apply {
                strokeWidth = width.toPx()
                this.color = color
                style = PaintingStyle.Stroke
                pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
            }
        it.drawRoundRect(
            width.toPx(),
            width.toPx(),
            size.width - width.toPx(),
            size.height - width.toPx(),
            radius.toPx(),
            radius.toPx(),
            paint
        )
    }
}

fun Modifier.shadowBottomEnd(
    elevation: Dp,
    color: Color = Color.Black.copy(alpha = 0.2f),
    shadowRadius: Dp = elevation * 2,
    offsetY: Dp = 0.dp,
    offsetX: Dp = 0.dp
) = this.drawBehind {
    val shadowPath = Path().apply {
        moveTo(0f, size.height - offsetY.toPx())
        lineTo(size.width - offsetX.toPx(), size.height - offsetY.toPx())
        lineTo(size.width - offsetX.toPx(), size.height)
        lineTo(0f, size.height)
        close()
    }
    drawIntoCanvas {
        it.drawPath(
            path = shadowPath,
            paint = Paint().apply {
                this.style = PaintingStyle.Stroke
                this.strokeWidth = shadowRadius.toPx()
                this.color = color
            }
        )
    }
}

fun Modifier.shadowBottomGradation(
    elevation: Dp,
    color: Color = Color.Black.copy(alpha = 0.2f),
    shadowRadius: Dp = elevation * 2,
    offsetY: Dp = 0.dp,
    offsetX: Dp = 0.dp
) = this.drawBehind {
    val shadowPath = Path().apply {
        moveTo(0f, size.height - offsetY.toPx())
        lineTo(size.width - offsetX.toPx(), size.height - offsetY.toPx())
        lineTo(size.width - offsetX.toPx(), size.height)
        lineTo(0f, size.height)
        close()
    }
    val gradientShader: Shader = LinearGradientShader(
        from = Offset(0f, size.height - offsetY.toPx()),
        to = Offset(0f, size.height),
        colors = listOf(color, Color.Transparent),
        tileMode = TileMode.Clamp
    )
    drawIntoCanvas {
        it.drawPath(
            path = shadowPath,
            paint = Paint().apply {
                this.style = PaintingStyle.Stroke
                this.strokeWidth = shadowRadius.toPx()
                this.shader = gradientShader
            }
        )
    }
}

@SuppressLint("ModifierFactoryUnreferencedReceiver")
fun Modifier.detectBackgroundTap(
    onTap: () -> Unit
): Modifier = this.pointerInput(Unit) {
    awaitPointerEventScope {
        while (true) {
            // Wait for any pointer event
            val event = awaitPointerEvent(PointerEventPass.Initial)

            // Check if it's a simple "down" event (the end of a tap)
            if (event.type == PointerEventType.Press) {
                // Execute the provided logic
                onTap()
            }

            // Important: We don't consume the event, so it continues
            // to be processed by children like LaserControlView for dragging.
        }
    }
}