# import lines needed to play sound files, drive NeoPixels, and control motor
import board, time, digitalio
from adafruit_debouncer import Button
from audiopwmio import PWMAudioOut as AudioOut
from audiocore import WaveFile
from audiomp3 import MP3Decoder
import neopixel

# -----------------------
# Set up button
# -----------------------
button = digitalio.DigitalInOut(board.GP14)
button.switch_to_input(pull=digitalio.Pull.UP)

# -----------------------
# Set up the speaker
# -----------------------
audio = AudioOut(board.GP10)

path = "/"
filename = "Defying-gravity.mp3"
mp3_file = open(path + filename, "rb")
decoder = MP3Decoder(mp3_file)

# -----------------------
# Set up NeoPixels
# -----------------------
NUM_PIXELS = 120
pixels = neopixel.NeoPixel(
    board.GP15, NUM_PIXELS,
    brightness=0.25, auto_write=False
)

# -----------------------
# Set up motor (L298N)
# -----------------------
in1 = digitalio.DigitalInOut(board.GP16)
in1.direction = digitalio.Direction.OUTPUT
in2 = digitalio.DigitalInOut(board.GP17)
in2.direction = digitalio.Direction.OUTPUT

def motor_on():
    in1.value = True
    in2.value = False

def motor_off():
    in1.value = False
    in2.value = False

# -----------------------
# Animation helpers
# -----------------------
def wheel(pos):
    """Convert 0-255 to an RGB rainbow color."""
    pos = pos % 256
    if pos < 85:
        return (pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return (255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return (0, pos * 3, 255 - pos * 3)

def anim_rainbow(step):
    for i in range(NUM_PIXELS):
        pixels[i] = wheel((i * 256 // NUM_PIXELS) + step * 2)
    pixels.show()

def anim_chase(step):
    color = wheel(step * 3)
    for i in range(NUM_PIXELS):
        pixels[i] = color if (i + step) % 3 == 0 else (0, 0, 0)
    pixels.show()

def anim_bounce(step):
    span = (NUM_PIXELS - 1) * 2
    pos = step % span
    if pos >= NUM_PIXELS:
        pos = span - pos
    color = wheel(step * 4)
    for i in range(NUM_PIXELS):
        distance = abs(i - pos)
        if distance == 0:
            pixels[i] = color
        elif distance <= 3:
            fade = 255 // (distance * 3 + 1)
            pixels[i] = tuple(c * fade // 255 for c in color)
        else:
            pixels[i] = (0, 0, 0)
    pixels.show()

ANIMATIONS = [anim_rainbow, anim_chase, anim_bounce]
ANIM_SWITCH_SEC = 5  # Switch animation every 5 seconds

def lights_off():
    pixels.fill((0, 0, 0))
    pixels.show()

# -----------------------
# Play MP3 + run lights + motor
# -----------------------
def play_show(filename):
    decoder.file = open(path + filename, "rb")
    motor_on()
    audio.play(decoder)

    start_time = time.monotonic()
    step = 0

    try:
        while audio.playing:
            elapsed = time.monotonic() - start_time
            anim_index = int(elapsed / ANIM_SWITCH_SEC) % len(ANIMATIONS)
            ANIMATIONS[anim_index](step)
            step += 1
            time.sleep(0.03)  # ~33 FPS
    finally:
        motor_off()
        lights_off()

# -----------------------
# Main loop
# -----------------------
lights_off()
motor_off()
print("Ready. Press button to start show.")

while True:
    if button.value == False:
        print("BUTTON IS PRESSED!")
        play_show(filename)
    time.sleep(0.02)