"""Trafiksignal-gubbe: röd står -> SAM -> gul springer -> grön går -> SAM -> gul springer -> ..."""
import machine, neopixel, time, random

PIN = 4
W, H = 8, 8
NUM = W * H
np = neopixel.NeoPixel(machine.Pin(PIN), NUM)

def xy(x, y):
    return y * W + x

def clear():
    for i in range(NUM):
        np[i] = (0, 0, 0)

RED = (24, 0, 0)
GREEN = (0, 24, 0)
YELLOW = (26, 22, 0)
TEXT = (24, 24, 12)

# --- sprites ---
STAND = [
    "...##...",
    "...##...",
    "..####..",
    ".######.",
    "..####..",
    "..####..",
    "..#..#..",
    ".##..##.",
]

# Gångcykel (4 frames)
WALK = [
    [   "...##...", "...##...", "..####..", ".#####..",
        "..####..", "...####.", "..##.#..", ".##...##" ],
    [   "...##...", "...##...", "..####..", "..####..",
        "..####..", "..####..", "..####..", "..#..#.." ],
    [   "...##...", "...##...", "..####..", "..#####.",
        "..####..", ".####...", "..#.##..", "##...##." ],
    [   "...##...", "...##...", "..####..", "..####..",
        "..####..", "..####..", "..####..", "..#..#.." ],
]

# Springcykel (2 frames för snabb alternering)
RUN = [
    [   "....##..", "....##..", "..####..", ".####...",
        "..####..", "...####.", ".##..#..", "##....##" ],
    [   "..##....", "..##....", "..####..", "...####.",
        "..####..", ".####...", "..#..##.", "##....##" ],
]

def draw(sprite, color):
    clear()
    for y in range(8):
        for x in range(8):
            if sprite[y][x] == '#':
                np[xy(x, y)] = color
    np.write()

def show_static(sprite, color, dur_ms):
    draw(sprite, color)
    time.sleep_ms(dur_ms)

def animate(frames, color, dur_ms, frame_ms):
    t0 = time.ticks_ms()
    i = 0
    while time.ticks_diff(time.ticks_ms(), t0) < dur_ms:
        draw(frames[i % len(frames)], color)
        time.sleep_ms(frame_ms)
        i += 1

# --- font (5x7) ---
FONT = {
    'S': [".###.", "#...#", "#....", ".###.", "....#", "#...#", ".###."],
    'A': [".###.", "#...#", "#...#", "#####", "#...#", "#...#", "#...#"],
    'M': ["#...#", "##.##", "#.#.#", "#...#", "#...#", "#...#", "#...#"],
}

def wheel(pos, peak=10):
    """0-255 -> RGB regnbåge med max `peak` per kanal."""
    pos &= 255
    if pos < 85:
        return (pos * peak // 85, (85 - pos) * peak // 85, 0)
    elif pos < 170:
        pos -= 85
        return ((85 - pos) * peak // 85, 0, pos * peak // 85)
    else:
        pos -= 170
        return (0, pos * peak // 85, (85 - pos) * peak // 85)

# Persistent sparkle-state: varje pixel har [hue, livstid 0..1]
_sparkle = [[0, 0.0] for _ in range(NUM)]

def show_letter_sparkle(ch, color, dur_ms=600, frame_ms=70):
    """Visa bokstav med regnbågs-glitter i bakgrunden (svagt lysande)."""
    glyph = FONT[ch]
    glyph_w = len(glyph[0])
    x0 = (W - glyph_w) // 2
    # Vilka pixlar tillhör bokstaven (ska inte få sparkles ovanpå)
    letter_pixels = set()
    for ry in range(7):
        for cx in range(glyph_w):
            if glyph[ry][cx] == '#':
                letter_pixels.add(xy(x0 + cx, ry))

    t0 = time.ticks_ms()
    while time.ticks_diff(time.ticks_ms(), t0) < dur_ms:
        # Spawna 2-3 nya gnistor på slumpvisa bakgrundspixlar
        for _ in range(3):
            idx = random.randint(0, NUM - 1)
            if idx not in letter_pixels:
                _sparkle[idx][0] = random.randint(0, 255)
                _sparkle[idx][1] = 1.0
        # Rendera bakgrund (svagt lysande, fadar)
        for i in range(NUM):
            if i in letter_pixels:
                continue
            hue, life = _sparkle[i]
            if life > 0:
                c = wheel(hue, peak=10)
                np[i] = (int(c[0] * life), int(c[1] * life), int(c[2] * life))
                _sparkle[i][1] = max(0.0, life - 0.10)
            else:
                np[i] = (0, 0, 0)
        # Bokstav ovanpå
        for idx in letter_pixels:
            np[idx] = color
        np.write()
        time.sleep_ms(frame_ms)

def show_text(text, color, letter_ms=600, gap_ms=120):
    for ch in text:
        show_letter_sparkle(ch, color, letter_ms)
        clear()
        np.write()
        time.sleep_ms(gap_ms)

# --- main loop ---
try:
    while True:
        show_static(STAND, RED, 5000)
        show_text("SAM", TEXT)
        animate(RUN, YELLOW, 1500, 90)
        animate(WALK, GREEN, 5000, 180)
        show_text("SAM", TEXT)
        animate(RUN, YELLOW, 1500, 90)
except KeyboardInterrupt:
    clear()
    np.write()
