"""Glitched-bundle för 8x8 NeoPixel på GPIO 4 / ESP32-C3.
Cyklar: vortex -> '46elks' scrollar med glitter -> Glitched G med glitter.
Lägg som main.py på nyflashat kort så går det igång automatiskt."""
import machine, neopixel, time, math, random

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

DIM = 24
CX, CY = 3.5, 3.5

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

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

def wheel(pos, peak=DIM):
    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)

def scale(c, f):
    return (int(c[0] * f), int(c[1] * f), int(c[2] * f))

# =================================================================
# Vortex: roterande spiralarmar
# =================================================================
def vortex(duration_ms=9000):
    t0 = time.ticks_ms()
    frame = 0
    while time.ticks_diff(time.ticks_ms(), t0) < duration_ms:
        for y in range(H):
            for x in range(W):
                dx, dy = x - CX, y - CY
                r = math.sqrt(dx * dx + dy * dy)
                a = math.atan2(dy, dx)
                hue = int(a * 40 + r * 28 - frame * 6) & 255
                bright = 0.35 + 0.65 * (0.5 + 0.5 * math.sin(r * 1.6 - frame * 0.28))
                np[xy(x, y)] = scale(wheel(hue), bright)
        np.write()
        frame += 1
        time.sleep_ms(35)

# =================================================================
# Glitter-bakgrund (persistent state med fade)
# =================================================================
_sparkle = [[0, 0.0] for _ in range(NUM)]

def update_sparkle(spawn_per_frame=3, fade_rate=0.08):
    for _ in range(spawn_per_frame):
        i = random.randint(0, NUM - 1)
        _sparkle[i][0] = random.randint(0, 255)
        _sparkle[i][1] = 1.0
    for i in range(NUM):
        if _sparkle[i][1] > 0:
            _sparkle[i][1] = max(0.0, _sparkle[i][1] - fade_rate)

def render_sparkle(skip_indices=None, peak=12):
    """Rita glitter; pixlar i skip_indices lämnas svarta (för att texten/loggan kan ritas över)."""
    if skip_indices is None:
        skip_indices = set()
    for i in range(NUM):
        if i in skip_indices:
            continue
        hue, life = _sparkle[i]
        if life > 0:
            c = wheel(hue, peak=peak)
            np[i] = (int(c[0] * life), int(c[1] * life), int(c[2] * life))
        else:
            np[i] = (0, 0, 0)

# =================================================================
# Glitched G (grövre — 2-pixel-tjocka kanter)
# =================================================================
GLITCHED_G = [
    ".######.",
    "########",
    "##......",
    "##.####.",
    "##.####.",
    "##......",
    "########",
    ".######.",
]

def show_g_with_glitter(duration_ms=6500):
    g_pixels = set()
    for y in range(8):
        for x in range(8):
            if GLITCHED_G[y][x] == '#':
                g_pixels.add(xy(x, y))
    t0 = time.ticks_ms()
    f = 0
    while time.ticks_diff(time.ticks_ms(), t0) < duration_ms:
        update_sparkle(spawn_per_frame=2, fade_rate=0.08)
        render_sparkle(skip_indices=g_pixels, peak=12)
        # G:t cyklar i regnbåge ovanpå
        g_color = wheel(f * 4, peak=DIM)
        for idx in g_pixels:
            np[idx] = g_color
        np.write()
        f += 1
        time.sleep_ms(55)

# =================================================================
# Scrollande '46elks' med glitter bakom
# =================================================================
FONT = {
    '4': ["00010", "00110", "01010", "10010", "11111", "00010", "00010"],
    '6': ["01110", "10000", "10000", "11110", "10001", "10001", "01110"],
    'e': ["00000", "00000", "01110", "10001", "11111", "10000", "01110"],
    'l': ["01100", "00100", "00100", "00100", "00100", "00100", "01110"],
    'k': ["10000", "10000", "10010", "10100", "11000", "10100", "10010"],
    's': ["00000", "00000", "01110", "10000", "01110", "00001", "11110"],
    ' ': ["00000"] * 7,
}

def text_columns(text):
    cols = []
    for ch in text:
        glyph = FONT[ch]
        w = len(glyph[0])
        for cx in range(w):
            col = 0
            for ry in range(7):
                if glyph[ry][cx] == '1':
                    col |= (1 << ry)
            cols.append(col)
        cols.append(0)
    return cols

def scroll_46elks_with_glitter(duration_ms=7000, step_ms=100):
    cols = text_columns("46elks")
    offset = -W
    text_color = (28, 28, 28)
    t0 = time.ticks_ms()
    while time.ticks_diff(time.ticks_ms(), t0) < duration_ms:
        # ta reda på vilka pixlar texten täcker just nu (för att hoppa över glitter där)
        text_pixels = set()
        for x in range(W):
            ci = offset + x
            if 0 <= ci < len(cols):
                col = cols[ci]
                for y in range(H):
                    if col & (1 << y):
                        text_pixels.add(xy(x, y))
        update_sparkle(spawn_per_frame=3, fade_rate=0.08)
        render_sparkle(skip_indices=text_pixels, peak=12)
        # text ovanpå
        for idx in text_pixels:
            np[idx] = text_color
        np.write()
        offset += 1
        if offset > len(cols):
            offset = -W
        time.sleep_ms(step_ms)

# =================================================================
# Huvudcykel
# =================================================================
try:
    while True:
        vortex(9000)
        scroll_46elks_with_glitter(8000)
        show_g_with_glitter(6500)
except KeyboardInterrupt:
    clear()
    np.write()
