package solutions.tretter.mindmachine.session

enum class FlashColor {
    RED,
    GREEN,
    BLACK,
}

data class SplitFlashFrame(
    val left: FlashColor,
    val right: FlashColor,
)

private const val MIN_INTERVAL_MS = 50
private const val MAX_INTERVAL_MS = 2000

private fun clampIntervalMs(value: Int): Long = value.coerceIn(MIN_INTERVAL_MS, MAX_INTERVAL_MS).toLong()

class SplitFlashSequencer(
    startTimeNanos: Long,
    flashOnMs: Int,
    flashOffMs: Int,
) {
    private var onMs: Long = clampIntervalMs(flashOnMs)
    private var offMs: Long = clampIntervalMs(flashOffMs)
    private var pendingOnMs: Long = onMs
    private var pendingOffMs: Long = offMs

    private var phase: Int = 0
    private var phaseStartNanos: Long = startTimeNanos

    fun updateIntervals(flashOnMs: Int, flashOffMs: Int) {
        pendingOnMs = clampIntervalMs(flashOnMs)
        pendingOffMs = clampIntervalMs(flashOffMs)
    }

    fun frameAt(frameTimeNanos: Long): SplitFlashFrame {
        if (frameTimeNanos < phaseStartNanos) {
            phaseStartNanos = frameTimeNanos
            phase = 0
        }

        while (frameTimeNanos - phaseStartNanos >= currentPhaseDurationNanos()) {
            phaseStartNanos += currentPhaseDurationNanos()
            phase = (phase + 1) % 4
            applyPendingIfBoundary()
        }

        return frameForPhase(phase)
    }

    private fun applyPendingIfBoundary() {
        if (phase == 0 || phase == 2) {
            onMs = pendingOnMs
        } else {
            offMs = pendingOffMs
        }
    }

    private fun currentPhaseDurationNanos(): Long {
        val durationMs = if (phase == 0 || phase == 2) onMs else offMs
        return durationMs * 1_000_000L
    }

    private fun frameForPhase(phase: Int): SplitFlashFrame = when (phase) {
        0 -> SplitFlashFrame(left = FlashColor.RED, right = FlashColor.GREEN)
        1 -> SplitFlashFrame(left = FlashColor.BLACK, right = FlashColor.BLACK)
        2 -> SplitFlashFrame(left = FlashColor.GREEN, right = FlashColor.RED)
        else -> SplitFlashFrame(left = FlashColor.BLACK, right = FlashColor.BLACK)
    }
}

fun computeSplitFlashFrame(
    frameTimeNanos: Long,
    flashOnMs: Int,
    flashOffMs: Int,
): SplitFlashFrame {
    val onMs = clampIntervalMs(flashOnMs)
    val offMs = clampIntervalMs(flashOffMs)
    val elapsedMs = frameTimeNanos / 1_000_000L

    // Four phases: on, off, on(swapped), off
    val total = 2L * (onMs + offMs)
    val t = if (total <= 0L) 0L else (elapsedMs % total)

    return when {
        t < onMs -> SplitFlashFrame(left = FlashColor.RED, right = FlashColor.GREEN)
        t < onMs + offMs -> SplitFlashFrame(left = FlashColor.BLACK, right = FlashColor.BLACK)
        t < 2L * onMs + offMs -> SplitFlashFrame(left = FlashColor.GREEN, right = FlashColor.RED)
        else -> SplitFlashFrame(left = FlashColor.BLACK, right = FlashColor.BLACK)
    }
}
