# PixelCraft Cube Controller
import board, neopixel, digitalio, pwmio
import time
import busio

import wifi
import socketpool

import sparkfun_qwiicrelay

pixels_length = 324 # at least for mine
pixels2_length = 111 # at least for mine

pixels = neopixel.NeoPixel(board.GP0, pixels_length, brightness = 0.5)
pixels2 = neopixel.NeoPixel(board.GP1, pixels2_length, brightness = 0.5)

pixels.fill((0,0,0))
pixels2.fill((0,0,0))
pixels.fill((255,255,255))
pixels2.fill((255,255,255))
time.sleep(3)
pixels.fill((0,0,0))
pixels2.fill((0,0,0))

# I2C on GP21 (SCL) and GP20 (SDA)
i2c = busio.I2C(scl=board.GP21, sda=board.GP20)

# create relay object at default address 0x18
relay = sparkfun_qwiicrelay.Sparkfun_QwiicRelay(i2c)
# or, if the alias exists:
# relay = sparkfun_qwiicrelay.QwiicRelay(i2c)

print("Relay connected:", relay.connected)

# turn relay ON for 3s, then OFF
relay.relay_on()
time.sleep(3)
relay.relay_off()

# Pico W = Access Point
ssid = "PixelCraft_Cube"
password = "123"

wifi.radio.start_ap(ssid=ssid, password=password)

print("Access Point active!")
print("SSID:", ssid)
print("Password:", password)
print("AP IP address:", wifi.radio.ipv4_address)

# ---------- HTTP SERVER SETUP ----------
pool = socketpool.SocketPool(wifi.radio)
server = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
server.settimeout(None)
server.bind(("0.0.0.0", 80))
server.listen(1)

print("HTTP server listening on port 80...")

# Pre-allocate a buffer for incoming request data
BUFFER_SIZE = 1024
buf = bytearray(BUFFER_SIZE)

def handle_swing(step):
    print("SWING event received!")
    steps = [8, 6, 4, 3, 1]
    colors = [DIAMOND_LOW, DIAMOND_LOW, DIAMOND_LOW, DIAMOND_HIGH, DIAMOND_HIGH]
    break_animation_step(steps[step], colors[step])
    if step == 4:
        # relay on
        relay.relay_on()
        
        time.sleep(0.2)
        pixels.fill((0,0,0))
        pixels2.fill((0,0,0))
        pixels.show()
        pixels2.show()

        time.sleep(3)
        # relay off
        relay.relay_off()

DIAMOND_LOW = (50, 125, 110)
DIAMOND_HIGH = (125, 255, 255)

def break_animation_step(step, color): # use steps 8(=unbroken) >> 6 >> 4 >> 3 >> 1 (=break)
    if step == 1:
        pixels.fill(color)
        pixels2.fill(color)
    else:
        for i in range(pixels_length):
            if (i % step) == 0:
                pixels[i] = color
        for i in range(pixels2_length):
            if (i % step) == 0:
                pixels2[i] = color

stage = 0
while True:
    try:
        client, addr = server.accept()
        print("Client connected:", addr)

        # Read into buffer
        n = client.recv_into(buf)
        if n == 0:
            client.close()
            continue

        # Slice buffer to actual length and decode
        request = bytes(buf[:n]).decode("utf-8")
        print("Request:\n", request)

        # Very simple path check for /swing
        if " /swing" in request:
            handle_swing(stage % 5) # does animations and things
            stage += 1
            response_body = "OK\n"
            status_line = "HTTP/1.1 200 OK\r\n"
        else:
            response_body = "Not Found\n"
            status_line = "HTTP/1.1 404 Not Found\r\n"

        headers = (
            "Content-Type: text/plain\r\n"
            f"Content-Length: {len(response_body)}\r\n"
            "Connection: close\r\n"
            "\r\n"
        )

        response = (status_line + headers + response_body).encode("utf-8")
        client.send(response)
        client.close()

    except Exception as e:
        print("Server error:", e)
        # Small delay so it doesn't spam if something goes wrong
        time.sleep(0.1)