from neopixel import Neopixel
import random
import utime
import math

print("test")
normal_repeats = 2  # Number of times the normal heartbeat pattern repeats
dying_cycles = 2   # Number of cycles for the dying rhythm

# Since a single normal heartbeat pattern consists of 2 cycles, and there are dying_cycles:
HEART_BEAT_CYCLES = (normal_repeats * 2) + dying_cycles

# This matrix which has 5 columns and 11 rows
# it describes the order in which the LEDs are wired
# to the microcontroller. The first LED is on the bottom left
# and starts up the first column, then goes down the second column
# and so on until it reaches the top of the fifth column.
led_portrat_matrix = [
    [10, 11, 32, 33, 54],
    [9, 12, 31, 34, 53],
    [8, 13, 30, 35, 52],
    [7, 14, 29, 36, 51],
    [6, 15, 28, 37, 50],
    [5, 16, 27, 38, 49],
    [4, 17, 26, 39, 48],
    [3, 18, 25, 40, 47],
    [2, 19, 24, 41, 46],
    [1, 20, 23, 42, 45],
    [0, 21, 22, 43, 44]]

#np = NeoPixel(machine.Pin(0), len(led_portrat_matrix) * len(led_portrat_matrix[0]))
np = Neopixel(55, 0, 6, "GRB")

# Given a item in the matrix, give an array of all items that are one row below it.
# If the item is in the last row, return None
def get_items_below(item):
    items_below = []
    for row in range(len(led_portrat_matrix)):
        for col in range(len(led_portrat_matrix[row])):
            if led_portrat_matrix[row][col] == item:
                # Append the items from the rows below the current row in the same column
                for below_row in range(row + 1, len(led_portrat_matrix)):
                    items_below.append(led_portrat_matrix[below_row][col])
                return items_below
    return None


def bleed_rhythm(item):
    items = get_items_below(item)
    for item in items:
        np[item] = (0, 255, 0)
        np.write()
        yield

def heart_beat_rhythm1(cycles):
    # Yields values between 0 and 255 to mimic a heartbeat brightness pattern
    for _ in range(cycles):
        for i in [50, 100, 150, 200, 255, 200, 150, 100, 50, 0]:
            yield i

def heart_beat_rhythm(normal_cycles, dying_cycles):
    # Normal heartbeats
    for _ in range(normal_cycles):  # Number of times to repeat the normal heartbeat pattern
        for cycle in range(2):  # A single normal heartbeat pattern
            for i in range(-90, 0, 10):
                yield int(255 * (1 + math.sin(math.radians(i))) / 2)
            for _ in range(2):
                yield int(255 * (1 + math.sin(math.radians(-90))) / 2)
            for i in range(-90, 0, 10):
                yield int(255 * (1 + math.sin(math.radians(i))) / 2)
            for _ in range(4):
                yield int(255 * (1 + math.sin(math.radians(-90))) / 2)

    last_brightness = 0
    # Dying rhythm
    for dying_cycle in range(1, dying_cycles + 1):  # Gradually reducing brightness
        for i in range(-90, 0, 10):
            yield int((255 / dying_cycle) * (1 + math.sin(math.radians(i))) / 2)
        for _ in range(2):
            yield int((200 / dying_cycle) * (1 + math.sin(math.radians(-90))) / 2)
        for i in range(-90, 0, 10):
            yield int((150 / dying_cycle) * (1 + math.sin(math.radians(i))) / 2)
        for _ in range(4):
            yield int((255 / dying_cycle) * (1 + math.sin(math.radians(-90))) / 2)
            


def fade_out(items_below, max_brightness):
    max_steps = max_brightness
    for step in range(max_steps):
        for index, row in enumerate(items_below):
            # Calculate the brightness based on the position in the array and the current step
            factor = (len(items_below) - 1 - index) / len(items_below)
            brightness = max(max_brightness - step * (1 + factor), 0)
            np.set_pixel(row, (0, int(brightness), 0))
            np.show()
        utime.sleep_ms(10)


excluded_first_row = [item for row in led_portrat_matrix[:-1] for item in row]

    # Run both generators simultaneously for 10 cycles
while True:
    chosen_pixel = random.choice(excluded_first_row)

    #chosen_pixel = random.randint(0, len(led_portrat_matrix) * len(led_portrat_matrix[0]) - 1)
    print(f"Chosen pixel: Index {chosen_pixel}")
    print(get_items_below(chosen_pixel))

    heart = heart_beat_rhythm(normal_repeats, dying_cycles)


    items_below = get_items_below(chosen_pixel)
    fade_in_values = [0] * len(items_below)
    current_item_below = 0  # Add this line to define the variable
    max_brightness = 0
    # Run both generators simultaneously for 10 cycles
    for cycle in range(HEART_BEAT_CYCLES *24 -1):
        brightness = next(heart)
        np.set_pixel(chosen_pixel,(0, brightness, 0))
        if brightness > 0 and cycle > random.randint(3, 12) and len(items_below) > 0:
            # Iterate through the LEDs and gradually increase brightness
            for index in range(min(current_item_below + 1, len(items_below))): 
                if fade_in_values[index] < brightness -10:
                    fade_in_values[index] += 5
                    max_brightness = fade_in_values[index]
                np.set_pixel(items_below[index], (0, min(255, int(fade_in_values[index])), 0))

            # Move on to the next LED if the current one has reached full brightness
            if fade_in_values[current_item_below] >= 25 and current_item_below < len(items_below) - 1:
                current_item_below += 1

        np.show()
        utime.sleep_ms(random.randint(50, 80))
        
    #np[chosen_pixel] = (0, 0, brightness)
    #items_below.insert(0, chosen_pixel)
    fade_out(items_below, max_brightness)









BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT