package com.performancecoachlab.posedetection.camera

import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.PaintingStyle.Companion.Fill
import androidx.compose.ui.graphics.PaintingStyle.Companion.Stroke
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.rotate
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import com.performancecoachlab.posedetection.recording.AnalysisResult
import com.performancecoachlab.posedetection.skeleton.Skeleton

fun ImageBitmap.drawSkeleton(
    inskeleton: Skeleton?, rotation: Float = 0f, mirrored: Boolean = false
): ImageBitmap {
    val skeleton = inskeleton?.let {
        if (mirrored) {
            it.mirror(this.height.toFloat())
        } else {
            it
        }
    }
    also {
        val bitmap = ImageBitmap(it.width, it.height)
        val canvas = Canvas(bitmap).apply {
            if (rotation != 0f) rotate(rotation, it.width.toFloat() / 2f, it.height.toFloat() / 2f)
        }
        val drawScope = CanvasDrawScope()
        val size = Size(it.width.toFloat(), it.height.toFloat())

        // Calculate scaling factor based on skeleton size
        val skeletonSize = skeleton?.joints()?.let { joints ->
            val minX = joints.minOfOrNull { joint -> joint.x } ?: 0f
            val maxX = joints.maxOfOrNull { joint -> joint.x } ?: 0f
            val minY = joints.minOfOrNull { joint -> joint.y } ?: 0f
            val maxY = joints.maxOfOrNull { joint -> joint.y } ?: 0f
            kotlin.math.min(maxX - minX, maxY - minY)
        } ?: 1f
        val scaleFactor = skeletonSize / kotlin.math.min(it.width, it.height)

        drawScope.draw(
            Density(1f),
            LayoutDirection.Ltr,
            canvas,
            size,
        ) {
            drawImage(it)

            skeleton?.apply {
                val baseStrokeWidth = 10f
                val scaledStrokeWidth = baseStrokeWidth * scaleFactor

                val paintWhite = Paint().apply {
                    color = Color.White
                    strokeWidth = scaledStrokeWidth
                    style = Stroke
                }
                val paintBlue = Paint().apply {
                    color = Color.Blue
                    strokeWidth = 0.8f * scaledStrokeWidth
                    style = Fill
                }
                bones().forEach { line ->
                    drawLine(
                        color = paintWhite.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintWhite.strokeWidth, blendMode = BlendMode.Softlight
                    )
                    drawLine(
                        color = paintBlue.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintBlue.strokeWidth, blendMode = BlendMode.Color
                    )
                }

                joints().forEach { joint ->
                    drawCircle(
                        brush = Brush.radialGradient(
                            colors = listOf(Color.Blue, Color.Transparent),
                            center = androidx.compose.ui.geometry.Offset(joint.x, joint.y),
                            radius = 1.2f * scaledStrokeWidth
                        ),
                        radius = 1.2f * scaledStrokeWidth,
                        center = androidx.compose.ui.geometry.Offset(joint.x, joint.y)
                    )
                }
            }
        }
        return bitmap
    }
}

fun ImageBitmap.drawResults(
    skeleton: Skeleton?, drawableObjects: List<DrawableObject>
): ImageBitmap {
    also {
        val bitmap = ImageBitmap(it.width, it.height)
        val canvas = Canvas(bitmap)
        val drawScope = CanvasDrawScope()
        val size = Size(it.width.toFloat(), it.height.toFloat())

        // Calculate scaling factor based on skeleton size
        val skeletonSize = skeleton?.joints()?.let { joints ->
            val minX = joints.minOfOrNull { joint -> joint.x } ?: 0f
            val maxX = joints.maxOfOrNull { joint -> joint.x } ?: 0f
            val minY = joints.minOfOrNull { joint -> joint.y } ?: 0f
            val maxY = joints.maxOfOrNull { joint -> joint.y } ?: 0f
            kotlin.math.max(maxX - minX, maxY - minY)
        } ?: 1f
        val minDime = kotlin.math.min(it.width, it.height).toFloat()
        val scaleFactor = skeletonSize / minDime
        val baseStrokeWidth = 30f
        val scaledStrokeWidth = (baseStrokeWidth * scaleFactor).coerceIn(2f, minDime / 50f)

        drawScope.draw(
            Density(1f),
            LayoutDirection.Ltr,
            canvas,
            size,
        ) {
            drawImage(it)
            for (drawableObject in drawableObjects) {
                when (drawableObject.shape) {
                    DrawableShape.OVAL -> drawOval(
                        color = drawableObject.colour,
                        topLeft = androidx.compose.ui.geometry.Offset(
                            drawableObject.obj.boundingBox.left, drawableObject.obj.boundingBox.top
                        ),
                        size = Size(
                            drawableObject.obj.boundingBox.width,
                            drawableObject.obj.boundingBox.height
                        ),
                        style = drawableObject.style
                    )

                    DrawableShape.RECTANGLE -> drawRect(
                        color = drawableObject.colour,
                        topLeft = androidx.compose.ui.geometry.Offset(
                            drawableObject.obj.boundingBox.left, drawableObject.obj.boundingBox.top
                        ),
                        size = Size(
                            drawableObject.obj.boundingBox.width,
                            drawableObject.obj.boundingBox.height
                        ),
                        style = drawableObject.style
                    )
                }
            }
            skeleton?.apply {
                val paintWhite = Paint().apply {
                    color = Color.White
                    strokeWidth = scaledStrokeWidth
                    style = Stroke
                }
                val paintBlue = Paint().apply {
                    color = Color.Blue
                    strokeWidth = 0.8f * scaledStrokeWidth
                    style = Fill
                }
                bones().forEach { line ->
                    drawLine(
                        color = paintWhite.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintWhite.strokeWidth, blendMode = BlendMode.Softlight
                    )
                    drawLine(
                        color = paintBlue.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintBlue.strokeWidth, blendMode = BlendMode.Color
                    )
                }

                joints().forEach { joint ->
                    drawCircle(
                        brush = Brush.radialGradient(
                            colors = listOf(Color.Blue, Color.Transparent),
                            center = androidx.compose.ui.geometry.Offset(joint.x, joint.y),
                            radius = 1.2f * scaledStrokeWidth
                        ),
                        radius = 1.2f * scaledStrokeWidth,
                        center = androidx.compose.ui.geometry.Offset(joint.x, joint.y)
                    )
                }
            }
        }
        return bitmap
    }
}

fun ImageBitmap.drawAnalysisResults(
    analysisResults: AnalysisResult, rotation: Float = 0f, mirrored: Boolean = false
): ImageBitmap {
    val skeleton = analysisResults.skeleton?.let {
        if (mirrored) {
            it.mirror(this.height.toFloat())
        } else {
            it
        }
    }
    also {
        val bitmap = ImageBitmap(it.width, it.height)
        val canvas = Canvas(bitmap).apply {
            if (rotation != 0f) rotate(
                rotation, it.width.toFloat() / 2f, it.height.toFloat() / 2f
            )
        }
        val drawScope = CanvasDrawScope()
        val size = Size(it.width.toFloat(), it.height.toFloat())

        // Calculate scaling factor based on skeleton size
        val skeletonSize = skeleton?.joints()?.let { joints ->
            val minX = joints.minOfOrNull { joint -> joint.x } ?: 0f
            val maxX = joints.maxOfOrNull { joint -> joint.x } ?: 0f
            val minY = joints.minOfOrNull { joint -> joint.y } ?: 0f
            val maxY = joints.maxOfOrNull { joint -> joint.y } ?: 0f
            kotlin.math.max(maxX - minX, maxY - minY)
        } ?: 1f
        val minDime = kotlin.math.min(it.width, it.height).toFloat()
        val scaleFactor = skeletonSize / minDime
        val baseStrokeWidth = 30f
        val scaledStrokeWidth = (baseStrokeWidth * scaleFactor).coerceIn(2f, minDime / 50f)

        drawScope.draw(
            Density(1f),
            LayoutDirection.Ltr,
            canvas,
            size,
        ) {
            drawImage(it)
            analysisResults.objects.forEach { analysisObject ->
                drawRect(
                    color = Color.Red, topLeft = androidx.compose.ui.geometry.Offset(
                        analysisObject.boundingBox.left, analysisObject.boundingBox.top
                    ), size = Size(
                        analysisObject.boundingBox.width, analysisObject.boundingBox.height
                    ), style = Stroke(scaledStrokeWidth)
                )
            }
            skeleton?.apply {

                val paintWhite = Paint().apply {
                    color = Color.White
                    strokeWidth = scaledStrokeWidth
                    style = Stroke
                }
                val paintBlue = Paint().apply {
                    color = Color.Blue
                    strokeWidth = 0.8f * scaledStrokeWidth
                    style = Fill
                }
                bones().forEach { line ->
                    drawLine(
                        color = paintWhite.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintWhite.strokeWidth, blendMode = BlendMode.Softlight
                    )
                    drawLine(
                        color = paintBlue.color, start = androidx.compose.ui.geometry.Offset(
                            line.first.x, line.first.y
                        ), end = androidx.compose.ui.geometry.Offset(
                            line.second.x, line.second.y
                        ), strokeWidth = paintBlue.strokeWidth, blendMode = BlendMode.Color
                    )
                }

                joints().forEach { joint ->
                    drawCircle(
                        brush = Brush.radialGradient(
                            colors = listOf(Color.Blue, Color.Transparent),
                            center = androidx.compose.ui.geometry.Offset(joint.x, joint.y),
                            radius = 1.2f * scaledStrokeWidth
                        ),
                        radius = 1.2f * scaledStrokeWidth,
                        center = androidx.compose.ui.geometry.Offset(joint.x, joint.y)
                    )
                }
            }
        }
        return bitmap
    }
}

expect enum class PlatformType {
    ANDROID, IOS;

    companion object {
        fun getCurrentPlatform(): PlatformType
    }
}