import board, time, busio, sdcardio, storage, digitalio, pwmio
from analogio import AnalogIn
from adafruit_debouncer import Button
from audiomp3 import MP3Decoder
from audiopwmio import PWMAudioOut as AudioOut

# =========== Setting up constant value ===================
MAX_STEPS = 2912
MAX_POTENTIOMETER = 65535
STEP_WINDOW = MAX_STEPS / 8
HALF_WINDOW = STEP_WINDOW / 2

# ========== Stepper Motor Setup ==========================
# Define the stepper motor control pins (GP4 to GP7)
pins = [
    digitalio.DigitalInOut(board.GP2),
    digitalio.DigitalInOut(board.GP3),
    digitalio.DigitalInOut(board.GP4),
    digitalio.DigitalInOut(board.GP5)
]

# Set each pin to output mode
for pin in pins:
    pin.direction = digitalio.Direction.OUTPUT

# Define the stepper motor sequence, one loop through will increment the gear once.
step_sequence = [
    [1, 0, 0, 0],
    [1, 1, 0, 0],
    [0, 1, 0, 0],
    [0, 1, 1, 0],
    [0, 0, 1, 0],
    [0, 0, 1, 1],
    [0, 0, 0, 1],
    [1, 0, 0, 1]
]

# ========== SD Card Setup ==========================
sck = board.GP10
si = board.GP11
so = board.GP12
cs = board.GP13
spi = busio.SPI(sck, si, so)
sdcard = sdcardio.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

# ========== Button Setup ==========================
button_pin = digitalio.DigitalInOut(board.GP7)
button_pin.switch_to_input(pull=digitalio.Pull.UP)
button = Button(button_pin)

# ========== Potentiometer Setup ==========================
potentiometer = AnalogIn(board.GP26)

# ========== Audio Setup ==========================
audio = AudioOut(board.GP15)
path = "/sd/make_art/"
filename = "pieta.mp3"
mp3_file = open(path + filename, "rb")
decoder = MP3Decoder(mp3_file)

# ========== Helper Functions ==========================
def play_mp3(filename):
    decoder.file.close()  # Close any previously open file
    decoder.file = open(path + filename, "rb")
    audio.play(decoder)
    while audio.playing:
        button.update()
        if button.pressed:
            audio.stop()  # Stop audio playback immediately
            return False
    return False

# Gives us the name if the audio file to play based off position. Note: Always start with La Pieta front anc center.
def map_step_to_audio(step_count):
    if 0 <= step_count<= HALF_WINDOW:
        return "pieta.mp3"
    elif (HALF_WINDOW + STEP_WINDOW) <= step_count <= (HALF_WINDOW + STEP_WINDOW * 2):
        return "ganymede.mp3"
    elif (HALF_WINDOW + STEP_WINDOW * 3) <=step_count <= (HALF_WINDOW + STEP_WINDOW * 4):
        return "atlas.mp3"
    elif (HALF_WINDOW + STEP_WINDOW * 5) <= step_count <= (HALF_WINDOW + STEP_WINDOW * 6):
        return "adonis.mp3"
    elif (HALF_WINDOW + STEP_WINDOW * 7) <= step_count <= MAX_STEPS:
        return "pieta.mp3"
    else:
        return "spinning.mp3"

# Takes the potentiometer reading and turns it into both a spin speed (delay) and a spin direction.
def translate_potentiometer(pot_reading):
    mapped_val = (pot_reading - (MAX_POTENTIOMETER / 2))
    spin_direction = -1 if mapped_val < 0 else 1
    mapped_val = abs(mapped_val)
    if mapped_val <= 8000:
        return 0, 0
    mapped_val = int((5 - ((mapped_val - 8000) / ((MAX_POTENTIOMETER / 2) - 8000 )) * (5 - 1))) / 1000
    return spin_direction, mapped_val

# Loops through the step sequence to move the gear one tick
def step_motor(direction, delay):
    for step in range(len(step_sequence))[::direction]:  # Adjust the loop direction based on `direction`
        for pin in range(4):
            pins[pin].value = step_sequence[step][pin]
        time.sleep(delay)

# ========== Main Loop ==========================
playing = False
current_step = 0
print("Lets start the Loop")
while True:
    direction, delay = translate_potentiometer(potentiometer.value)
    button.update()
    if button.pressed:
        playing = True
    if playing:
        filename = map_step_to_audio(current_step)
        print(f"Playing: {filename}")
        playing = play_mp3(filename)
    if direction != 0:
        step_motor(direction, delay)
        current_step = (current_step + direction) % (MAX_STEPS + 1)
