package mg.dot.feufaro.solfa

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.runtime.mutableStateOf
import androidx.compose.material3.ExperimentalMaterial3Api // Nécessaire pour ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.DropdownMenu
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.IconButton
import androidx.compose.ui.unit.dp

class Transpose {
    companion object {
        val REGEX_ONE_NOTE = Regex("^([drmfslt][ia]?)([₄₃₂₁¹²³⁴',]*)(.*)")
        val octaveSigns = listOf("₄", "₃", "₂", "₁", "", "¹", "²", "³", "⁴")
        val noteToNumber = listOf("d", "di", "r", "ri", "m", "f", "fi", "s", "si", "l", "ta", "t")
        val keyToNumber = listOf("C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" )
        val keyToArmature = listOf(0,   -7,   2,  -3,   4,   -1,  -6,   1,    -4,  3,   -2,   5  )
        fun compareNotes(note1: String, note2: String): Int {
            val found1 = REGEX_ONE_NOTE.find(note1)
            val found2 = REGEX_ONE_NOTE.find(note2)
            if (found1 == null || found2 == null) {
                return 0
            }
            val octave1 = octaveSigns.indexOf(found1.groupValues[2])
            val octave2 = octaveSigns.indexOf(found2.groupValues[2])
            return when {
                octave1 < octave2 -> -1
                octave1 > octave2 -> 1
                else -> {
                    val noteNum1 = noteToNumber.indexOf(found1.groupValues[1])
                    val noteNum2 = noteToNumber.indexOf(found2.groupValues[1])
                    when {
                        noteNum1 > noteNum2 -> 1
                        noteNum1 < noteNum2 -> -1
                        else -> 0
                    }
                }
            }
        }
        fun toArmature(note: String): Int {
            val index = keyToNumber.indexOf(note)
            return keyToArmature.getOrNull(index) ?: 0
        }
        fun transposeMidi(note: String, fromKey: String) : Pair<String, Int> {
            return Pair(note, 4)
        }
        fun simplifyNoteMidi(note: String): Pair<String, Int> {
            var octaveFin = 4
            val indexOctave = octaveSigns.mapIndexed { index, sign -> sign to index}.toMap()
            val outputBuilder = StringBuilder()
            for (char in note) {
                when (char) {
                    ',' -> octaveFin--
                    '\'' -> octaveFin++
                    else -> {
                        val octaveNum = indexOctave[char.toString()]
                        if (octaveNum != null) {
                            octaveFin += octaveNum - 4
                        } else {
                            outputBuilder.append(char)
                        }
                    }
                }
            }
            return Pair(outputBuilder.toString(), octaveFin)
        }
        fun simplifyNote(note: String): String {
            val simplifiedMidi = simplifyNoteMidi(note)
            return simplifiedMidi.first + octaveSigns[simplifiedMidi.second]
        }
        fun transposeToSolfa(note: String, fromKey: String, toKey: String, alter: Int = 0): String {
            val transposed = transpose(note, fromKey, toKey, alter)
            return transposed
                .replace("di", "D")
                .replace("ri", "R")
                .replace("fi", "F")
                .replace("si", "S")
                .replace("ta", "T")
        }
        fun transposeToMidi(note: String, fromKey: String, toKey: String, alter:Int = 0): Int {
            val transposed = transpose(note, fromKey, toKey, alter)
            val noteNaked = REGEX_ONE_NOTE.find(transposed)
            val noteNum = noteToNumber.indexOf(noteNaked?.groupValues[1])
            val octave =  octaveSigns.indexOf(noteNaked?.groupValues[2])
            //val returnValue = midiKeys.getOrNull(noteNum)  + octave.toString()
            val returnValue = 12*octave + noteNum + 12
            return returnValue
        }
        fun transposeToFeufaroo(note: String, fromKey: String, toKey: String, alter: Int = 0): Pair<String, Int> {
            val transposed = transpose(note, fromKey, toKey, alter)
            return simplifyNoteMidi(transposed)
        }
        fun transpose(note: String, fromKey: String, toKey: String, alter: Int = 0, toSolfaCode: Boolean = false): String {
            val regexFound = REGEX_ONE_NOTE.find(note)
            if (regexFound == null) {
                return note
            }
            val noteNaked = regexFound.groupValues[1]
            val noteNum = noteToNumber.indexOf(noteNaked)
            val oldKey = keyToNumber.indexOf(fromKey)
            val newKey = keyToNumber.indexOf(toKey)
            var newNoteNum = noteNum - newKey + oldKey + alter
            var suffix = ""
            val noteSize = noteToNumber.size
            if (newNoteNum < 0) {
               newNoteNum += noteSize
               suffix = ","
            }
            if (newNoteNum >= noteSize) {
                newNoteNum -= noteSize
                suffix = "'"
            }
            val newNote = noteToNumber[newNoteNum] + regexFound.groupValues[2] + suffix
            return  simplifyNote(newNote) + regexFound.groupValues[3]
        }
        @OptIn(ExperimentalMaterial3Api::class) // Ajoutez cette annotation pour utiliser ExposedDropdownMenuBox
        @Composable
        fun chooseKey(
            modifier: Modifier = Modifier,
            label: String = "Choose a key",
            menuItemData: List<String> = keyToNumber,
            onOptionSelected: (String) -> Unit
        ) {
            var expanded by remember { mutableStateOf(false) }
            Box(
                modifier = modifier
                    .padding(0.dp)
            ) {
                IconButton(onClick = {expanded = !expanded}) {
                    Icon(Icons.Default.ArrowDropDown, contentDescription = label)
                }
                DropdownMenu(
                    expanded = expanded,
                    onDismissRequest = { expanded = false}
                ) {
                    menuItemData.forEach { option ->
                        DropdownMenuItem(
                            text = { Text(option)},
                            onClick = {
                                onOptionSelected(option)
                                expanded = false
                            }
                        )
                    }
                }
            }
        }
    }
}