"""
reggaeton_helpers.py - Helpers for reggaeton music generation.

T055-T056: Populate harmony track and note name conversion.
"""

NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
NOTE_ALIASES = {
    'DB': 'C#', 'EB': 'D#', 'GB': 'F#', 'AB': 'G#', 'BB': 'A#',
    'CB': 'B', 'FB': 'E'
}


def note_name_to_midi(note_name: str) -> int:
    """
    T056: Convert note name (e.g., "A3", "C4") to MIDI number.
    
    Args:
        note_name: Note name (e.g., "A3", "C4", "F#4")
    
    Returns:
        MIDI number (0-127)
    """
    note_name = note_name.strip().upper()
    
    if len(note_name) < 2:
        return 60
    
    if len(note_name) >= 2 and note_name[1] == '#':
        note = note_name[:2]
        octave = int(note_name[2:]) if len(note_name) > 2 else 4
    elif len(note_name) >= 2 and note_name[1] == 'B':
        note = note_name[:2]
        octave = int(note_name[2:]) if len(note_name) > 2 else 4
    else:
        note = note_name[0]
        octave = int(note_name[1:]) if len(note_name) > 1 else 4
    
    note = NOTE_ALIASES.get(note, note)
    
    if note not in NOTE_NAMES:
        return 60
    
    note_index = NOTE_NAMES.index(note)
    midi_number = (octave + 1) * 12 + note_index
    
    return midi_number


REGGAETON_HARMONY_PROGRESSION = [
    (0,   32, [('A3', 1.0), ('C4', 0.5), ('E4', 0.5)]),
    (32,  32, [('F3', 1.0), ('A3', 0.5), ('C4', 0.5)]),
    (64,  32, [('G3', 1.0), ('B3', 0.5), ('D4', 0.5)]),
    (96,  32, [('E3', 1.0), ('G3', 0.5), ('B3', 0.5)]),
    (128, 32, [('A3', 1.0), ('C4', 0.5), ('E4', 0.5)]),
    (160, 32, [('F3', 1.0), ('A3', 0.5), ('C4', 0.5)]),
    (192, 32, [('G3', 1.0), ('D4', 1.0), ('B3', 0.5)]),
    (224, 32, [('A3', 2.0), ('E4', 2.0)]),
]

AM_SCALE_NOTES = [69, 71, 72, 74, 76, 77, 79]


def quantize_to_am_scale(note: int) -> int:
    """
    T054: Quantize a MIDI note to the Am natural scale.
    
    Args:
        note: MIDI note number
    
    Returns:
        Nearest note in Am natural scale
    """
    if note in AM_SCALE_NOTES:
        return note
    
    nearest = min(AM_SCALE_NOTES, key=lambda x: abs(x - note))
    return nearest