package com.radiola.ui.components

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.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
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.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.dp
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin

/** Стиль анимации воспроизведения (выбирается пользователем в настройках). */
enum class VisualizerStyle(val key: String, val label: String) {
    BARS_CENTER("bars_center", "Центр"),
    BARS_BOTTOM("bars_bottom", "Снизу"),
    WAVE("wave", "Волна"),
    RADIAL("radial", "Круг");

    companion object {
        fun fromKey(k: String?): VisualizerStyle = entries.firstOrNull { it.key == k } ?: BARS_CENTER
    }
}

/**
 * Визуализатор звука выбранного стиля. levels — реальный спектр (0..1 по полосам);
 * если его нет (пауза/превью) — мягкая «дышащая» анимация.
 */
@Composable
fun Visualizer(
    style: VisualizerStyle,
    levels: FloatArray?,
    playing: Boolean,
    color: Color,
    modifier: Modifier = Modifier,
) {
    val phase by rememberInfiniteTransition(label = "viz").animateFloat(
        initialValue = 0f,
        targetValue = (Math.PI * 2).toFloat(),
        animationSpec = infiniteRepeatable(tween(1400, easing = LinearEasing), RepeatMode.Restart),
        label = "vizPhase",
    )
    Canvas(modifier = modifier) {
        when (style) {
            VisualizerStyle.BARS_CENTER -> drawBars(levels, phase, playing, color, centered = true)
            VisualizerStyle.BARS_BOTTOM -> drawBars(levels, phase, playing, color, centered = false)
            VisualizerStyle.WAVE -> drawWave(levels, phase, playing, color)
            VisualizerStyle.RADIAL -> drawRadial(levels, phase, playing, color)
        }
    }
}

/** Уровень полосы i из n: реальный спектр → иначе «дышащая» синус-волна. */
private fun levelAt(i: Int, n: Int, levels: FloatArray?, phase: Float, playing: Boolean): Float {
    if (!playing) return 0.16f
    if (levels != null && levels.isNotEmpty()) {
        val idx = (i * levels.size / n).coerceIn(0, levels.size - 1)
        return (0.06f + 0.94f * levels[idx]).coerceIn(0f, 1f)
    }
    return 0.42f + 0.5f * abs(sin(phase + i * 0.7f))
}

private fun DrawScope.drawBars(
    levels: FloatArray?,
    phase: Float,
    playing: Boolean,
    color: Color,
    centered: Boolean,
) {
    val barCount = 36
    val gap = 3.dp.toPx()
    val barWidth = (size.width - gap * (barCount - 1)) / barCount
    val maxH = size.height
    for (i in 0 until barCount) {
        val h = maxH * levelAt(i, barCount, levels, phase, playing)
        val x = i * (barWidth + gap)
        val y = if (centered) (maxH - h) / 2f else (maxH - h)
        drawRoundRect(
            color = color,
            topLeft = Offset(x, y),
            size = Size(barWidth, h),
            cornerRadius = CornerRadius(barWidth / 2f, barWidth / 2f),
        )
    }
}

private fun DrawScope.drawWave(levels: FloatArray?, phase: Float, playing: Boolean, color: Color) {
    val points = 48
    val maxH = size.height
    val stepX = size.width / (points - 1)
    val ys = FloatArray(points) { i -> maxH * (1f - levelAt(i, points, levels, phase, playing)) }

    val line = Path()
    val fill = Path()
    line.moveTo(0f, ys[0])
    fill.moveTo(0f, maxH)
    fill.lineTo(0f, ys[0])
    for (i in 1 until points) {
        val x = i * stepX
        val px = (i - 1) * stepX
        val midX = (px + x) / 2f
        // Сглаживание кубическими кривыми между точками.
        line.cubicTo(midX, ys[i - 1], midX, ys[i], x, ys[i])
        fill.cubicTo(midX, ys[i - 1], midX, ys[i], x, ys[i])
    }
    fill.lineTo(size.width, maxH)
    fill.close()
    drawPath(fill, color = color.copy(alpha = 0.18f))
    drawPath(line, color = color, style = Stroke(width = 2.5.dp.toPx(), cap = StrokeCap.Round))
}

private fun DrawScope.drawRadial(levels: FloatArray?, phase: Float, playing: Boolean, color: Color) {
    val n = 40
    val cx = size.width / 2f
    val cy = size.height / 2f
    val rInner = minOf(cx, cy) * 0.42f
    val rMax = minOf(cx, cy) * 0.98f
    val stroke = (2 * Math.PI * rInner / n / 2).toFloat().coerceIn(2f, 6f)
    // тонкое кольцо-основа
    drawCircle(color = color.copy(alpha = 0.25f), radius = rInner * 0.9f, center = Offset(cx, cy), style = Stroke(1.5.dp.toPx()))
    for (i in 0 until n) {
        val lv = levelAt(i, n, levels, phase, playing)
        val ang = (i.toFloat() / n) * (2 * Math.PI).toFloat() - (Math.PI / 2).toFloat()
        val len = rInner + (rMax - rInner) * lv
        val sx = cx + cos(ang) * rInner
        val sy = cy + sin(ang) * rInner
        val ex = cx + cos(ang) * len
        val ey = cy + sin(ang) * len
        drawLine(
            color = color,
            start = Offset(sx, sy),
            end = Offset(ex, ey),
            strokeWidth = stroke,
            cap = StrokeCap.Round,
        )
    }
}
