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

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.zIndex
import com.iscs.bozzys.R
import com.iscs.bozzys.api.Node
import com.iscs.bozzys.ui.pages.compose.CardBox
import com.iscs.bozzys.ui.theme.Main
import com.iscs.bozzys.ui.theme.Text

/**
 * 布局之间的连线操作（贝塞尔曲线）
 *
 * @param nodes         所有节点列表
 * @param connections   所有连接的信息
 * @param scale         缩放比例
 */
@Composable
fun ConnectionLayer(nodes: Map<String, NodeUI>, connections: List<Connection>, scale: Float) {
    val modifier = Modifier
        .fillMaxSize()
        .zIndex(2f)
    Canvas(modifier = modifier) {
        connections.forEach { conn ->
            // 起始点
            val from = nodes[conn.fromId]
            // 到达点
            val to = nodes[conn.toId]

            if (from != null && to != null) {
                // 处理需要绘制的所有点位
                val pathPoints = orthogonalPath(fromNodeUI = from, fromAnchor = conn.fromAnchor, toNodeUI = to, toAnchor = conn.toAnchor)
                // 连接所有线段
                val path = Path().apply {
                    moveTo(pathPoints.first().x, pathPoints.first().y)
                    for (i in 1 until pathPoints.size) {
                        lineTo(pathPoints[i].x, pathPoints[i].y)
                    }
                }
                // 绘制线段
                drawPath(path = path, color = Main, style = Stroke(width = 3f * scale, cap = StrokeCap.Round, join = StrokeJoin.Round))
            }
        }
    }
}

/**
 * 流程节点样式
 *
 * @param id            当前节点唯一标识
 * @param nodes         所有节点
 * @param selectNodeUI  当前选中的节点
 * @param onNodeClick   当前节点被点击
 * @param modifier      节点样式
 */
@Composable
fun NodeItem(
    id: String,
    nodes: SnapshotStateMap<String, NodeUI>,
    selectNodeUI: MutableState<NodeUI>,
    onNodeClick: (NodeUI) -> Unit,
    modifier: Modifier = Modifier
) {
    // 当前item的节点
    val node = nodes[id] ?: return
    val isSelect = selectNodeUI.value.id == node.id
    // 是否已完成的节点
    val finished = node.node?.approvalStatus == "approved"
    // 是否进行中的节点
    val running = node.node?.approvalStatus == "running"
    // 处理卡片阴影颜色
    val shadowColor = if (isSelect) {
        MaterialTheme.colorScheme.primary.copy(alpha = 0.25f)
    } else {
        // 比对当前节点是否已完成，已完成显示绿色
        if (running) Color(0xFF3B82F6).copy(alpha = 0.25f)
        else if (finished) Color(0xFF00C950).copy(alpha = 0.25f)
        else Color.Black.copy(alpha = 0.15f)
    }
    // 处理卡片边框颜色
    val colorBorder = if (isSelect) {
        MaterialTheme.colorScheme.primary
    } else {
        if (running) Color(0xFF3B82F6)
        else if (finished) Color(0xFF00C950)
        else Color.White
    }
    // 处理当前进行中的节点闪烁提示
    val infiniteTransition = rememberInfiniteTransition()
    val alpha by infiniteTransition.animateFloat(
        initialValue = 0.2f,
        targetValue = 0.8f,
        animationSpec = infiniteRepeatable(animation = tween(durationMillis = 1000, easing = LinearEasing), repeatMode = RepeatMode.Reverse)
    )
    CardBox(
        modifier = modifier
            .size(node.baseSize.width.dp, node.baseSize.height.dp)
            .offset(node.position.x.dp, node.position.y.dp)
            .onGloballyPositioned { coordinates ->
                nodes[id] = NodeUI(
                    id = id,
                    position = node.position,
                    offset = coordinates.positionInParent(),
                    size = coordinates.size.toSize(),
                    node = node.node
                )
            },
        shadowColor = shadowColor
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .border(2.dp, color = colorBorder.copy(alpha = if (running) alpha else 1f), shape = RoundedCornerShape(12.dp))
                .clickable(onClick = { onNodeClick(node) })
                .padding(10.dp)
        ) {
            Icon(
                painter = painterResource(node.node?.getIcon() ?: R.mipmap.logo),
                contentDescription = "",
                modifier = Modifier
                    .size(26.dp)
                    .clip(RoundedCornerShape(30))
                    .background(Color(0xFF3B82F6))
                    .padding(5.dp),
                tint = Color.White
            )
            Spacer(Modifier.weight(2f))
            Text(node.node?.nodeName ?: "", fontSize = 12.sp, lineHeight = 12.sp, fontWeight = FontWeight.Bold, color = Text)
            Spacer(Modifier.weight(1f))
            Text("ID：${node.node?.id ?: 0}", fontSize = 10.sp, lineHeight = 10.sp, color = Color(0xFF999999))
        }
    }
}

/**
 * 通过节点获取四面连接点的位置信息
 *
 * @param anchor    连接的点位信息
 */
fun NodeUI.anchor(anchor: Anchor): Offset = when (anchor) {
    Anchor.LEFT -> Offset(offset.x, offset.y + size.height / 2)
    Anchor.RIGHT -> Offset(offset.x + size.width, offset.y + size.height / 2)
    Anchor.TOP -> Offset(offset.x + size.width / 2, offset.y)
    Anchor.BOTTOM -> Offset(offset.x + size.width / 2, offset.y + size.height)
}

/**
 * 绘制正交连接线
 *
 * @param fromNodeUI      起始位置节点信息
 * @param fromAnchor    起始位置的连接点位置
 * @param toNodeUI        终点位置节点信息
 * @param toAnchor      终点位置的连接点位置
 * @param padding       起始/终点位置添加padding值
 */
private fun orthogonalPath(fromNodeUI: NodeUI, fromAnchor: Anchor, toNodeUI: NodeUI, toAnchor: Anchor, padding: Float = 40f): List<Offset> {
    val from = fromNodeUI.anchor(fromAnchor)
    val to = toNodeUI.anchor(toAnchor)
    // 处理连接的点位
    val points = mutableListOf<Offset>()
    // 起点出线
    var fromOut = when (fromAnchor) {
        Anchor.LEFT -> Offset(from.x - padding, from.y)
        Anchor.RIGHT -> Offset(from.x + padding, from.y)
        Anchor.TOP -> Offset(from.x, from.y - padding)
        Anchor.BOTTOM -> Offset(from.x, from.y + padding)
    }
    // 终点入线
    var toIn = when (toAnchor) {
        Anchor.LEFT -> Offset(to.x - padding, to.y)
        Anchor.RIGHT -> Offset(to.x + padding, to.y)
        Anchor.TOP -> Offset(to.x, to.y - padding)
        Anchor.BOTTOM -> Offset(to.x, to.y + padding)
    }


    val midPoints = mutableListOf<Offset>()
    // 绘制中间连线
    if (fromAnchor == Anchor.BOTTOM) {
        when (toAnchor) {
            // 只需要绘制一个点
            Anchor.LEFT -> midPoints += Offset(fromOut.x, toIn.y)
            // 顶部需要绘制两个点才能变成直线
            Anchor.TOP -> {
                val y = if (toIn.y - fromOut.y < 0) {
                    fromOut = fromOut.copy(y = from.y)
                    toIn = toIn.copy(y = to.y)
                    from.y + (to.y - from.y) / 2
                } else {
                    fromOut.y + (toIn.y - fromOut.y) / 2
                }
                midPoints += Offset(fromOut.x, y)
                midPoints += Offset(toIn.x, y)
            }

            else -> {}
        }
    } else if (fromAnchor == Anchor.RIGHT) {
        when (toAnchor) {
            Anchor.LEFT -> {
                val x = if (toIn.x - fromOut.x < 0) {
                    fromOut = fromOut.copy(x = from.x)
                    toIn = toIn.copy(x = to.x)
                    from.x + (to.x - from.x) / 2
                } else {
                    fromOut.x + (toIn.x - fromOut.x) / 2
                }
                midPoints += Offset(x, fromOut.y)
                midPoints += Offset(x, toIn.y)
            }

            else -> {}
        }
    }

    // 将起点和起点出线绘制好
    points += from
    points += fromOut
    // 绘制中间点
    points += midPoints
    // 绘制结束连线
    points += toIn
    points += to

    return points
}

/**
 * 节点定义
 *
 * @param id        用于记录当前节点唯一标记，用于后续连线或者offset和size在缩放布局中的绝对定位
 * @param position  当前控件的绝对定位
 * @param offset    在父控件中的位置
 * @param size      在父控件中的尺寸
 * @param baseSize  控件原始尺寸
 * @param node      携带当前节点对象
 */
data class NodeUI(
    val id: String,
    val position: Offset,
    val offset: Offset = Offset(0f, 0f),
    val size: Size = Size(100f, 80f),
    val baseSize: Size = Size(100f, 80f),
    val node: Node? = null,
)

/**
 * 定义连线位置
 */
enum class Anchor {
    LEFT, RIGHT, TOP, BOTTOM
}

/**
 * 定义连线信息
 *
 * @param fromId        起始ID
 * @param toId          终点ID
 * @param fromAnchor    来源起始位置
 * @param toAnchor      终点结束位置
 */
data class Connection(
    val fromId: String,
    val toId: String,
    val fromAnchor: Anchor = Anchor.RIGHT,
    val toAnchor: Anchor = Anchor.LEFT
)