// SPDX-FileCopyrightText: 2026 Reactorcoremeltdown
// SPDX-License-Identifier: GPL-3.0-or-later

package space.rcmd.android.sizzle.ui.components

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import space.rcmd.android.sizzle.ui.theme.LocalRetro

/**
 * Lays out one octave as a real piano keyboard: seven white keys across the bottom
 * with the five black keys overlaid on top, each centred on the gap between the two
 * white keys it sits between (C# D# _ F# G# A#).
 *
 * Layout-only: the [key] slot renders each key and callers attach their own gesture
 * to [keyModifier] (tap-to-enter, hold-to-audition, …). Black keys are emitted last
 * so they draw — and receive touches — on top of the white keys they overlap, just
 * like a physical keyboard.
 */
@Composable
fun PianoOctave(
    modifier: Modifier = Modifier,
    blackWidthFraction: Float = 0.62f,
    blackHeightFraction: Float = 0.62f,
    key: @Composable (pitchClass: Int, isBlack: Boolean, keyModifier: Modifier) -> Unit,
) {
    BoxWithConstraints(modifier) {
        val whiteW = maxWidth / 7
        val blackW = whiteW * blackWidthFraction
        val blackH = maxHeight * blackHeightFraction
        // White keys: C D E F G A B, filling the width evenly.
        Row(Modifier.fillMaxSize()) {
            for (pc in WHITE_PCS) key(pc, false, Modifier.weight(1f).fillMaxHeight())
        }
        // Black keys, each centred on the boundary after a given white-key index.
        for ((pc, afterWhite) in BLACK_PCS) {
            key(
                pc, true,
                Modifier
                    .offset(x = whiteW * (afterWhite + 1) - blackW / 2)
                    .width(blackW)
                    .height(blackH),
            )
        }
    }
}

/**
 * A single piano key face: light for white keys, dark for black, dimmed when
 * [enabled] is false and accent-filled when [selected]. [pressed] lights the key
 * in the accent colour while it is held down (from any input source) — the visual
 * feedback shared by every keyboard widget. The gesture (if any) is supplied by the
 * caller through [modifier].
 */
@Composable
fun PianoKey(
    label: String,
    isBlack: Boolean,
    enabled: Boolean,
    selected: Boolean,
    modifier: Modifier,
    pressed: Boolean = false,
) {
    val c = LocalRetro.current
    val lit = selected || pressed
    val bg = when {
        lit -> c.accent
        isBlack -> if (enabled) BLACK_KEY else BLACK_KEY_OFF
        else -> if (enabled) WHITE_KEY else WHITE_KEY_OFF
    }
    val fg = when {
        lit -> c.background
        isBlack -> if (enabled) Color(0xFFDDDDDD) else Color(0xFF555555)
        else -> if (enabled) Color(0xFF141414) else Color(0xFF6A6A6A)
    }
    Box(
        modifier
            .background(bg)
            .border(1.dp, if (lit) c.accent else KEY_BORDER, RectangleShape),
        contentAlignment = Alignment.BottomCenter,
    ) {
        Text(
            label, color = fg, fontFamily = FontFamily.Monospace, fontSize = 12.sp,
            maxLines = 1, softWrap = false,
            modifier = Modifier.padding(bottom = 3.dp),
        )
    }
}

private val WHITE_PCS = intArrayOf(0, 2, 4, 5, 7, 9, 11)          // C D E F G A B
// pitch class -> index of the white key it sits immediately after (0=C .. 6=B).
private val BLACK_PCS = listOf(1 to 0, 3 to 1, 6 to 3, 8 to 4, 10 to 5)
private val WHITE_KEY = Color(0xFFE8E8E8)
private val WHITE_KEY_OFF = Color(0xFF5A5A5A)
private val BLACK_KEY = Color(0xFF181820)
private val BLACK_KEY_OFF = Color(0xFF0C0C10)
private val KEY_BORDER = Color(0xFF000000)
