package com.iscs.bozzys.ui.pages.edit.step.compose

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.spring
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.rememberTransformableState
import androidx.compose.foundation.gestures.transformable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.iscs.bozzys.R
import com.iscs.bozzys.event.RefreshEvent
import com.iscs.bozzys.event.RefreshEventBus
import com.iscs.bozzys.ui.pages.compose.CardBox
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlin.math.ceil
import kotlin.math.floor

/**
 * 可缩放和移动操作
 *
 * @param nodes         所有节点
 * @param connections   节点间的连线方式
 * @param modifier      样式配置
 * @param content       子控件
 */
@Composable
fun ZoomPanContainer(
    nodes: Map<String, NodeUI>,
    connections: List<Connection>,
    defaultScale: Float = 1f,
    scaleMin: Float = 0.5f,
    scaleMax: Float = 1.5f,
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.(Float, (NodeUI) -> Unit, (NodeUI) -> Unit, () -> Unit) -> Unit
) {
    val scope = rememberCoroutineScope()
    val scale = remember { Animatable(defaultScale) }
    val offsetX = remember { Animatable(0f) }
    val offsetY = remember { Animatable(0f) }
    // 记录上一次位置，手动触发和缩放控件触发有效
    var lastOffset by remember { mutableStateOf(Offset(0f, 0f)) }
    // 当前容器大小
    var containerSize by remember { mutableStateOf(IntSize.Zero) }

    val transformState = rememberTransformableState { zoomChange, panChange, _ ->
        scope.launch {
            scale.snapTo(targetValue = (scale.value * zoomChange).coerceIn(scaleMin, scaleMax))
            offsetX.snapTo(offsetX.value + panChange.x)
            offsetY.snapTo(offsetY.value + panChange.y)
            // 先保存上一次的位置
            lastOffset = Offset(offsetX.value, offsetY.value)
        }
    }

    /**
     * 动画移动当前节点到屏幕中间
     */
    fun animateNodeToTopCenter(nodeUI: NodeUI) {
        if (containerSize == IntSize.Zero) return
        // 找到容器的中心点位置，高度为控件可用空间的1/5处
        val center = Offset(containerSize.width / 2f, (containerSize.height / 4f) / 2f)
        // 计算偏移量
        val targetOffset = center - nodeUI.offset * scale.value

        // 执行动画移动到中心点
        val ox = targetOffset.x - (nodeUI.size.width / 2f) * scale.value
        val oy = targetOffset.y - (nodeUI.size.height / 2f) * scale.value
        scope.launch {
            launch { offsetX.animateTo(ox, spring()) }
            launch { offsetY.animateTo(oy, spring()) }
        }
    }

    /**
     * 动画移动当前节点到屏幕中间
     */
    fun animateNodeToCenter(nodeUI: NodeUI) {
        if (containerSize == IntSize.Zero) return
        // 找到容器的中心点位置，高度为控件可用空间的1/5处
        val center = Offset(containerSize.width / 2f, containerSize.height / 2f)
        // 计算偏移量
        val targetOffset = center - nodeUI.offset * scale.value

        // 执行动画移动到中心点
        val ox = targetOffset.x - (nodeUI.size.width / 2f) * scale.value
        val oy = targetOffset.y - (nodeUI.size.height / 2f) * scale.value
        scope.launch {
            launch { offsetX.animateTo(ox, spring()) }
            launch { offsetY.animateTo(oy, spring()) }
        }
    }

    /**
     * 移动到上一次位置
     */
    fun animateLastPosition() {
        scope.launch {
            launch { offsetX.animateTo(lastOffset.x, spring()) }
            launch { offsetY.animateTo(lastOffset.y, spring()) }
        }
    }

    LaunchedEffect(Unit) {
        async {
            RefreshEventBus.events.collect {
                when (it) {
                    is RefreshEvent.UpdateNodeToMapTopCenter -> animateNodeToTopCenter(it.value as NodeUI)
                    else -> {}
                }
            }
        }
    }

    Box(
        modifier = modifier
            .clipToBounds()
            .background(Color(0xFFF8F9FA))
            .onSizeChanged { containerSize = it }
            .transformable(transformState)
    ) {
        // 右上角缩放控件
        CardBox(
            modifier = Modifier
                .zIndex(6f)
                .padding(10.dp)
                .align(Alignment.TopEnd)
        ) {
            Column(
                Modifier
                    .width(40.dp)
                    .background(Color.White)
            ) {
                Icon(
                    painter = painterResource(R.drawable.plus), contentDescription = null, modifier = Modifier
                        .size(40.dp)
                        .clickable(onClick = {
                            scope.launch {
                                scale.animateTo(
                                    targetValue = (scale.value + 0.15f).coerceIn(scaleMin, scaleMax),
                                    animationSpec = spring(dampingRatio = 0.85f, stiffness = 300f)
                                )
                            }
                        })
                        .padding(12.dp),
                    tint = Color.Black
                )
                Spacer(
                    Modifier
                        .fillMaxWidth()
                        .height(1.dp)
                        .background(Color(0xFFE1E1E1))
                )
                Icon(
                    painter = painterResource(R.drawable.reduce), contentDescription = null, modifier = Modifier
                        .size(40.dp)
                        .clickable(onClick = {
                            scope.launch {
                                scale.animateTo(
                                    targetValue = (scale.value - 0.15f).coerceIn(scaleMin, scaleMax),
                                    animationSpec = spring(dampingRatio = 0.85f, stiffness = 300f)
                                )
                            }
                        })
                        .padding(12.dp),
                    tint = Color.Black
                )
            }
        }
        // 可缩放和拖拽布局
        Box(
            modifier = Modifier.graphicsLayer {
                transformOrigin = TransformOrigin(0f, 0f)
                scaleX = scale.value
                scaleY = scale.value
                translationX = offsetX.value
                translationY = offsetY.value
                // lastOffset = Offset(offsetX.value, offsetY.value)
            }
        ) {
            // 点阵背景
            InfiniteDotBackground(scale = scale.value, offset = Offset(offsetX.value, offsetY.value))
            // 连接线操作
            if (nodes.isNotEmpty()) ConnectionLayer(nodes, connections, scale = scale.value)
            // 外部自定义子控件
            content(scale.value, ::animateNodeToTopCenter, ::animateNodeToCenter, ::animateLastPosition)
        }
    }
}

/**
 * 缩放画布底下增加背景圆点
 */
@Composable
fun InfiniteDotBackground(
    scale: Float,
    offset: Offset,
    gap: Float = 50f,
    radius: Float = 2f,
    color: Color = Color(0xFFD1D1D1)
) {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .zIndex(1f)
    ) {

        // 屏幕 → 画布坐标
        val left = -offset.x / scale
        val top = -offset.y / scale
        val right = left + size.width / scale
        val bottom = top + size.height / scale

        // 外扩范围（至少 2～3 个 gap）
        val padding = gap * 3

        val startX = floor((left - padding) / gap) * gap
        val startY = floor((top - padding) / gap) * gap
        val endX = ceil((right + padding) / gap) * gap
        val endY = ceil((bottom + padding) / gap) * gap

        var x = startX
        while (x <= endX) {
            var y = startY
            while (y <= endY) {
                drawCircle(color = color, radius = radius, center = Offset(x, y))
                y += gap
            }
            x += gap
        }
    }
}


