"""Cyklande scenarier:
  plasma -> vortex (spiral) -> tunnel (sug-in) -> glitter -> text '6446.se' med skimmer
"""
import machine, neopixel, time, random, math

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

DIM = 24       # tak för "ljusa" effekter
DIM_BG = 4     # tak för bakgrundsskimmer bakom text
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):
    """0-255 -> RGB med tak `peak` per kanal."""
    pos &= 255
    third = peak * 3
    if pos < 85:
        return (pos * third // 765, (255 - pos * 3) * peak // 765, 0)
    elif pos < 170:
        pos -= 85
        return ((255 - pos * 3) * peak // 765, 0, pos * third // 765)
    else:
        pos -= 170
        return (0, pos * third // 765, (255 - pos * 3) * peak // 765)

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

def bg_color(hue, peak=6):
    """Som wheel men minst 1 per kanal — bakgrund blir alltid fylld, aldrig svart."""
    pos = hue & 255
    span = peak - 1
    if pos < 85:
        r = 1 + pos * span // 85
        g = 1 + (85 - pos) * span // 85
        b = 1
    elif pos < 170:
        pos -= 85
        r = 1 + (85 - pos) * span // 85
        g = 1
        b = 1 + pos * span // 85
    else:
        pos -= 170
        r = 1
        g = 1 + pos * span // 85
        b = 1 + (85 - pos) * span // 85
    return (r, g, b)

# =================================================================
# Effekt 1: plasma (klassisk demoscene — flytande färgmoln)
# =================================================================
def plasma(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):
                v = (math.sin(x * 0.7 + frame * 0.10)
                     + math.sin(y * 0.9 + frame * 0.13)
                     + math.sin((x + y) * 0.5 + frame * 0.08)
                     + math.sin(math.sqrt((x - CX) ** 2 + (y - CY) ** 2) + frame * 0.15))
                hue = int(v * 40 + frame * 2) & 255
                np[xy(x, y)] = wheel(hue)
        np.write()
        frame += 1
        time.sleep_ms(35)

# =================================================================
# Effekt 2: 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 följer vinkeln + spiraltvist beroende på radie + rotation över tid
                hue = int(a * 40 + r * 28 - frame * 6) & 255
                # ljuspuls inåt så det känns som armar
                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)

# =================================================================
# Effekt 3: tunnel — koncentriska ringar suger inåt
# =================================================================
def tunnel(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)
                # ringar flyter inåt (negativ riktning), liten vridning för djupkänsla
                phase = frame * 0.45 - r * 1.7 + a * 0.4
                bright = (0.5 + 0.5 * math.sin(phase)) ** 2
                hue = int(r * 50 + frame * 3) & 255
                np[xy(x, y)] = scale(wheel(hue), bright)
        np.write()
        frame += 1
        time.sleep_ms(35)

# =================================================================
# Effekt 4: glitter (random sparkles)
# =================================================================
def sparkle(duration_ms=7000):
    state = [[0, 0.0] for _ in range(NUM)]
    t0 = time.ticks_ms()
    while time.ticks_diff(time.ticks_ms(), t0) < duration_ms:
        for _ in range(2):
            i = random.randint(0, NUM - 1)
            state[i][0] = random.randint(0, 255)
            state[i][1] = 1.0
        for i in range(NUM):
            hue, inten = state[i]
            if inten > 0:
                np[i] = scale(wheel(hue), inten)
                state[i][1] = max(0.0, inten - 0.08)
            else:
                np[i] = (0, 0, 0)
        np.write()
        time.sleep_ms(40)

# =================================================================
# Effekt 5: scrollande text "6446.se" med skimmer-bakgrund
# =================================================================
FONT = {
    '6': ["01110", "10000", "10000", "11110", "10001", "10001", "01110"],
    '4': ["00010", "00110", "01010", "10010", "11111", "00010", "00010"],
    '.': ["00000", "00000", "00000", "00000", "00000", "00000", "01100"],
    's': ["00000", "00000", "01110", "10000", "01110", "00001", "11110"],
    'e': ["00000", "00000", "01110", "10001", "11111", "10000", "01110"],
    ' ': ["00000"] * 7,
}

def text_columns(text):
    cols = []
    for ch in text:
        glyph = FONT.get(ch, FONT[' '])
        char_w = len(glyph[0])
        for cx in range(char_w):
            col = 0
            for ry in range(7):
                if glyph[ry][cx] == '1':
                    col |= (1 << ry)
            cols.append(col)
        cols.append(0)  # mellanrum mellan tecken
    return cols

def scroll_text_shimmer(text, text_color=(DIM, DIM, DIM), duration_ms=15000):
    cols = text_columns(text)
    t0 = time.ticks_ms()
    offset = -W
    frame = 0
    while time.ticks_diff(time.ticks_ms(), t0) < duration_ms:
        # bakgrund: fyllt plasmaskimmer, varje pixel alltid färgad
        for y in range(H):
            for x in range(W):
                v = (math.sin(x * 0.55 + frame * 0.06)
                     + math.sin(y * 0.7 + frame * 0.08)
                     + math.sin((x + y) * 0.4 + frame * 0.05))
                hue = int(v * 50 + frame * 2) & 255
                np[xy(x, y)] = bg_color(hue, peak=6)
        # text ovanpå
        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):
                        np[xy(x, y)] = text_color
        np.write()
        offset += 1
        frame += 1
        if offset > len(cols):
            offset = -W
        time.sleep_ms(80)

# =================================================================
# Cykla allt
# =================================================================
try:
    while True:
        plasma(9000)
        vortex(9000)
        tunnel(9000)
        sparkle(6000)
        scroll_text_shimmer("6446.se", duration_ms=15000)
except KeyboardInterrupt:
    clear()
    np.write()
