import board
import neopixel
import digitalio
from adafruit_debouncer import Button
import time
import random
import math

PIXEL_PIN = board.GP0
NUM_PIXELS = 256
BRIGHTNESS = 0.1
WIDTH = 16
HEIGHT = 16

grid = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, auto_write=False, brightness=BRIGHTNESS)

RED = (255, 0, 0)
ORANGE = (255, 165, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
BLUE= (0,0,255)

# Helper: Convert (x, y) to pixel index in a top-left 0-indexed serpentine grid
def xy_to_index(x, y):
    if y % 2 == 0:
        return y * WIDTH + x  # even row: left to right
    else:
        return y * WIDTH + (WIDTH - 1 - x)

# Indices for the "5" digit (RED)
five_pixels = [93, 98, 125, 130, 157, 162, 189, 92, 99, 124, 131, 156, 163, 188, 91, 100, 90, 101, 89, 102, 88,
103, 87, 104, 120, 135, 152, 167, 184, 119, 136, 151, 168, 183, 169, 182, 170, 181, 171, 180, 172, 179, 173, 178, 83,
108, 115, 140, 147, 82, 109, 114, 141, 146]

# Indices for the "10" digit (GREEN)
ten_pixels = [31, 61, 28, 65, 94, 66, 93, 67, 92, 68, 91, 69, 90, 70, 89, 71, 88, 72, 87, 73, 86, 74, 85, 75, 84,
76, 83, 77, 82, 44, 51, 45, 50, 108, 115, 109, 114, 158, 161, 157, 162, 156, 163, 155, 164, 154, 165, 153, 166, 152,
167, 151, 168, 150, 169, 149, 170, 148, 171, 147, 172, 146, 173, 222, 225, 221, 226, 220, 227, 219, 228, 218, 229, 217, 230, 216, 231,
215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 190, 193, 189, 194, 179, 204, 178, 205]

fifteen_pixels = [28, 34, 19, 44, 51, 76, 83, 108, 18, 45, 50, 77, 82, 109, 62, 65, 61, 66, 60, 67, 59, 68, 58, 69, 57, 70, 56, 71,
55, 72, 54, 73, 53, 74, 52, 75, 130, 157, 162, 189, 194, 221, 226, 131, 156, 163, 188, 195, 220, 227, 132, 155, 133, 154, 134, 153, 135,
152, 136, 151, 167, 184, 199, 216, 231, 168, 183, 200, 215, 232, 214, 233, 213, 234, 212, 235,
211, 236, 210, 237, 140, 147, 172, 179, 204, 141, 146, 173, 178, 205]

twenty_pixels = [30, 33, 62, 65, 94, 97, 126, 29, 34, 61, 66, 93, 98, 125, 158, 161, 190, 193, 222, 225, 157,
162, 189, 194, 221, 226, 99, 124, 100, 123, 101, 122, 102, 121, 103, 120, 104, 119, 24, 39, 56, 71, 88, 23, 40, 55, 72,
87, 22, 41, 21, 42, 20, 43, 19, 44, 18, 45, 51, 76, 83, 108, 115, 50, 77, 82, 109, 114, 156, 163, 155, 164, 154, 165, 153, 166, 152,
167, 151, 168, 150, 169, 149, 170, 148, 171, 147, 172, 146, 173, 220, 227, 219, 228, 218, 229, 217, 230, 216, 231, 215,
232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 179, 204, 178, 205]

twenty_five_pixels = [29, 34, 61, 66, 93, 98, 28, 35, 60, 67, 92, 99, 91, 100, 90, 101, 89, 102, 88, 103, 87, 104, 24, 39, 56, 71, 23, 40,
55, 72, 22, 41, 21, 42, 20, 43, 19, 44, 18, 45, 51, 76, 83, 108, 50, 77, 82, 109, 130, 157, 162, 189, 194, 221, 226, 131, 156, 163, 188, 195, 220,
227, 132, 155, 133, 154, 134, 153, 135, 152, 136, 151, 167, 184, 199, 216, 231, 168, 183, 200, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210,
237, 140, 147, 172, 179, 204, 141, 146, 173, 178, 205]

thirty_pixels = [30, 33, 62, 65, 94, 97, 126, 158, 161, 190, 193, 222, 225, 29, 34, 61, 66, 93, 98, 125, 157, 162, 189, 194, 221, 226, 99, 124, 100, 123,
101, 122, 102, 121, 103, 120, 104, 119, 105, 118, 106, 117, 107, 116, 108, 115, 109, 114, 24, 39, 56, 71, 88, 23, 40, 55, 72, 87, 19, 44, 51, 76, 83, 18,
45, 50, 77, 82, 156, 163, 155, 164, 154, 165, 153, 166, 152, 167, 151, 168, 150, 169, 149, 170, 148, 171, 147, 172, 146, 173, 220, 227, 219, 228, 218, 229,
217, 230, 216, 231, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 179, 204, 178, 205]

thirty_five_pixels = [29, 34, 61, 66, 93, 98, 28, 35, 60, 67, 92, 99, 91, 100, 90, 101, 89, 102, 88, 103, 87, 104, 86, 105, 85, 106, 84, 107, 83, 108, 82,
109, 24, 39, 56, 71, 23, 40, 55, 72, 19, 44, 51, 76, 18, 45, 50, 77, 130, 157, 162, 189, 194, 221, 226, 131, 156, 163, 188, 195, 220, 227, 132, 155, 133,
154, 134, 153, 135, 152, 136, 151, 167, 184, 199, 216, 231, 168, 183, 200, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 140, 147, 172, 179,
204, 141, 146, 173, 178, 205]

forty_pixels = [30, 33, 29, 34, 28, 35, 27, 36, 26, 37, 25, 38, 24, 39, 23, 40, 97, 126, 98, 125, 99, 124, 100, 123, 101, 122, 102, 121, 103, 120, 104, 119,
105, 118, 106, 117, 107, 116, 108, 115, 109, 114, 56, 71, 88, 55, 72, 87, 158, 161, 157, 162, 156, 163, 155, 164, 154, 165, 153, 166, 152, 167, 151, 168, 150,
169, 149, 170, 148, 171, 147, 172, 146, 173, 222, 225, 221, 226, 220, 227, 219, 228, 218, 229, 217, 230, 216, 231, 215, 232, 214, 233, 213, 234, 212, 235, 211,
236, 210, 237, 190, 193, 189, 194, 179, 204, 178, 205]

forty_five_pixels = [29, 34, 28, 35, 27, 36, 26, 37, 25, 38, 24, 39, 23, 40, 56, 71, 55, 72, 93, 98, 92, 99, 91, 100, 90, 101, 89, 102, 88, 103, 87, 104, 86,
105, 85, 106, 84, 107, 83, 108, 82, 109, 130, 157, 162, 189, 194, 221, 226, 131, 156, 163, 188, 195, 220, 227, 132, 155, 133, 154, 134, 153, 135, 152, 136,
151, 167, 184, 199, 216, 231, 168, 183, 200, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 140, 147, 172, 179, 204, 141, 146, 173, 178, 205]

fifty_pixels = [29, 34, 61, 66, 93, 98, 125, 28, 35, 60, 67, 92, 99, 124, 27, 36, 26, 37, 25, 38, 24, 39, 23, 40, 56, 71, 88, 103, 120, 55, 72, 87, 104,
119, 105, 118, 106, 117, 107, 116, 108, 115, 109, 114, 19, 44, 51, 76, 83, 18, 45, 50, 77, 82, 157, 162, 189, 194, 221, 226, 156, 163, 188, 195, 220, 227,
155, 164, 154, 165, 153, 166, 152, 167, 151, 168, 150, 169, 149, 170, 148, 171, 147, 172, 146, 173, 179, 204, 178, 205, 219, 228, 218, 229, 217, 230, 216,
231, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237]

fifty_five_pixels = [29, 34, 61, 66, 93, 98, 125, 28, 35, 60, 67, 92, 99, 124, 27, 36, 26, 37, 25, 38, 24, 39, 23, 40, 56, 71, 88, 103, 120, 55, 72, 87,
104, 119, 105, 118, 106, 117, 107, 116, 108, 115, 109, 114, 19, 44, 51, 76, 83, 18, 45, 50, 77, 82, 157, 162, 189, 194, 221, 226, 253, 156, 163, 188, 195,
220, 227, 252, 155, 164, 154, 165, 153, 166, 152, 167, 151, 168, 184, 199, 216, 231, 248, 183, 200, 215, 232, 247, 233, 246, 234, 245, 235, 244, 236, 243,
237, 242, 147, 172, 179, 204, 211, 146, 173, 178, 205, 210]

sixty_pixels = [29, 34, 61, 66, 93, 98, 125, 28, 35, 60, 67, 92, 99, 124, 27, 36, 26, 37, 25, 38, 24, 39, 23, 40, 22, 41, 21, 42, 20, 43, 19, 44, 18, 45,
56, 71, 88, 103, 120, 55, 72, 87, 104, 119, 51, 76, 83, 108, 115, 50, 77, 82, 109, 114, 105, 118, 106, 117, 107, 116, 157, 162, 189, 194, 221, 226, 156,
163, 188, 195, 220, 227, 155, 164, 154, 165, 153, 166, 152, 167, 151, 168, 150, 169, 149, 170, 148, 171, 147, 172, 146, 173, 219, 228, 218, 229, 217, 230,
216, 231, 215, 232, 214, 233, 213, 234, 212, 235, 211, 236, 210, 237, 179, 204, 178, 205]

fill_order = [
        15, 16, 47, 48, 79, 80, 111, 112, 143, 144, 175, 176, 207, 208, 239, 240,
        14, 17, 46, 49, 78, 81, 110, 113, 142, 145, 174, 177, 206, 209, 238, 241,
        13, 18, 45, 50, 77, 82, 109, 114, 141, 146, 173, 178, 205, 210, 237, 242,
        12, 19, 44, 51, 76, 83, 108, 115, 140, 147, 172, 179, 204, 211, 236, 243,
        11, 20, 43, 52, 75, 84, 107, 116, 139, 148, 171, 180, 203, 212, 235, 244,
        10, 21, 42, 53, 74, 85, 106, 117, 138, 149, 170, 181, 202, 213, 234, 245,
        9, 22, 41, 54, 73, 86, 105, 118, 137, 150, 169, 182, 201, 214, 233, 246,
        8, 23, 40, 55, 72, 87, 104, 119, 136, 151, 168, 183, 200, 215, 232, 247,
        7, 24, 39, 56, 71, 88, 103, 120, 135, 152, 167, 184, 199, 216, 231, 248,
        6, 25, 38, 57, 70, 89, 102, 121, 134, 153, 166, 185, 198, 217, 230, 249,
        5, 26, 37, 58, 69, 90, 101, 122, 133, 154, 165, 186, 197, 218, 229, 250,
        4, 27, 36, 59, 68, 91, 100, 123, 132, 155, 164, 187, 196, 219, 228, 251,
        3, 28, 35, 60, 67, 92, 99, 124, 131, 156, 163, 188, 195, 220, 227, 252,
        2, 29, 34, 61, 66, 93, 98, 125, 130, 157, 162, 189, 194, 221, 226, 253,
        1, 30, 33, 62, 65, 94, 97, 126, 129, 158, 161, 190, 193, 222, 225, 254,
        0, 31, 32, 63, 64, 95, 96, 127, 128, 159, 160, 191, 192, 223, 224, 255
    ]

# Mapping of number to pixel lists
number_map = {
    5: five_pixels,
    10: ten_pixels,
    15: fifteen_pixels,
    20: twenty_pixels,
    25: twenty_five_pixels,
    30: thirty_pixels,
    35: thirty_five_pixels,
    40: forty_pixels,
    45: forty_five_pixels,
    50: fifty_pixels,
    55: fifty_five_pixels,
    60: sixty_pixels
}


pin_to_seconds = {
    board.GP21: 5,
    board.GP20: 10,
    board.GP17: 15,
    board.GP22: 20,
    board.GP26: 25,
    board.GP19: 30,
    board.GP10: 40,
    board.GP8: 45,
    board.GP3: 50,
    board.GP4: 55,
    board.GP14: 60
}
start_pin = board.GP16
reset_pin = board.GP18
play_pause_pin = board.GP11
party_pin = board.GP15

# Setup buttons
buttons = {}
for pin, secs in pin_to_seconds.items():
    dio = digitalio.DigitalInOut(pin)
    dio.switch_to_input(pull=digitalio.Pull.UP)
    buttons[secs] = Button(dio)

start_button_io = digitalio.DigitalInOut(start_pin)
start_button_io.switch_to_input(pull=digitalio.Pull.UP)
start_button = Button(start_button_io)

reset_button_io = digitalio.DigitalInOut(reset_pin)
reset_button_io.switch_to_input(pull=digitalio.Pull.UP)
reset_button = Button(reset_button_io)

play_pause_io = digitalio.DigitalInOut(play_pause_pin)
play_pause_io.switch_to_input(pull=digitalio.Pull.UP)
play_pause_button = Button(play_pause_io)

party_io = digitalio.DigitalInOut(party_pin)
party_io.switch_to_input(pull=digitalio.Pull.UP)
party_button = Button(party_io)

selected_time = None

def display_number(seconds):
    grid.fill(BLUE)
    for i in number_map[seconds]:
        if 0 <= i < NUM_PIXELS:
            grid[i] = RED
    grid.show()

def run_timer(seconds):
    global paused

    # --- 3, 2, 1 Countdown ---
    for color in [RED, ORANGE, GREEN]:
        reset_button.update()
        if reset_button.fell:
            print("Reset during countdown!")
            grid.fill(BLACK)
            grid.show()
            return

        grid.fill(color)
        grid.show()
        time.sleep(1)
    grid.fill(BLACK)
    grid.show()

    total_pixels = len(fill_order)
    delay = seconds / total_pixels
    color = RED
    stage = total_pixels // 3

    i = 0
    while i < total_pixels:
        pixel_index = fill_order[i]

        # Check for Reset
        reset_button.update()
        if reset_button.fell:
            print("Reset during timer!")
            grid.fill(BLACK)
            grid.show()
            return

        # Check for Play/Pause
        play_pause_button.update()
        if play_pause_button.fell:
            paused = not paused
            print("Paused" if paused else "Resumed")

        # If paused, wait and don't increment i
        if paused:
            time.sleep(0.1)
            continue

        # Handle color stages
        if i == stage:
            color = ORANGE
            for j in range(i):
                grid[fill_order[j]] = color
        elif i == 2 * stage:
            color = GREEN
            for j in range(i):
                grid[fill_order[j]] = color

        grid[pixel_index] = color
        grid.show()
        time.sleep(delay)
        i += 1

print("Ready. Press time button, then Start.")

def index_to_xy(index):
    y = index // 16
    x = index % 16 if y % 2 == 0 else 15 - (index % 16)
    return (x, y)

def xy_to_index(x, y):
    if 0 <= x < 16 and 0 <= y < 16:
        return y * 16 + x if y % 2 == 0 else y * 16 + (15 - x)
    return -1  # Invalid index

def draw_circle_burst(center_index, radius, color):
    cx, cy = index_to_xy(center_index)

    for angle in range(0, 360, 30):  # 12 points around the circle
        rad = math.radians(angle)
        x = round(cx + radius * math.cos(rad))
        y = round(cy + radius * math.sin(rad))
        idx = xy_to_index(x, y)
        if 0 <= idx < NUM_PIXELS:
            grid[idx] = color

    # Center pixel too
    if 0 <= center_index < NUM_PIXELS:
        grid[center_index] = color

def party_mode(duration=15):
    print("🎉 Circular Rainbow Fireworks!")

    rainbow_colors = [
        (255, 0, 0),     # Red
        (255, 127, 0),   # Orange
        (255, 255, 0),   # Yellow
        (0, 255, 0),     # Green
        (0, 0, 255),     # Blue
        (75, 0, 130),    # Indigo
        (148, 0, 211)    # Violet
    ]

    end_time = time.monotonic() + duration

    while time.monotonic() < end_time:
        grid.fill(BLACK)

        # Draw a few bursts per frame
        for _ in range(3):
            center = random.randint(16, NUM_PIXELS - 17)
            color = random.choice(rainbow_colors)
            draw_circle_burst(center, radius=2, color=color)

        grid.show()
        time.sleep(0.1)

    grid.fill(BLACK)
    grid.show()
    print("🎊 Fireworks party over!")

paused = False
running = False
while True:
    for secs, btn in buttons.items():
        btn.update()
        if btn.fell and not running:  # 🔧 Only allow changing if not running
            selected_time = secs
            print(f"Selected: {selected_time} seconds")
            display_number(selected_time)

    start_button.update()
    if start_button.fell and selected_time and not running:
        print(f"Starting timer for {selected_time} seconds")
        running = True
        run_timer(selected_time)
        running = False
        selected_time = None  # Reset after timer ends

    reset_button.update()
    if reset_button.fell:
        print("Reset button pressed!")
        grid.fill(BLACK)
        grid.show()
        selected_time = None
        running = False
        paused = False
        time.sleep(0.25)


    party_button.update()
    if party_button.fell:
        print("Button pressed on: board.GP15 - party")
        running = False
        paused = False
        selected_time = None
        grid.fill(BLACK)
        grid.show()
        party_mode()

    time.sleep(0.01)
