import time
import random
import board
import busio
import displayio
import rgbmatrix
import framebufferio
import adafruit_vl53l1x
import terminalio
from adafruit_display_text import label

disp_rel = displayio.release_displays
disp_rel()
mtx = rgbmatrix.RGBMatrix(width=64, height=32, bit_depth=4,rgb_pins=[board.MTX_R1, board.MTX_G1, board.MTX_B1, board.MTX_R2, board.MTX_G2, board.MTX_B2],addr_pins=[board.MTX_ADDRA, board.MTX_ADDRB, board.MTX_ADDRC, board.MTX_ADDRD],clock_pin=board.MTX_CLK, latch_pin=board.MTX_LAT, output_enable_pin=board.MTX_OE)

disp = framebufferio.FramebufferDisplay(mtx, auto_refresh=False)

i2c_bus = busio.I2C(board.SCL, board.SDA)

tca_addr = 0x70
chan0 = 0x01
chan3 = 0x08


def chswitch(ch_mask):
    while not i2c_bus.try_lock():
        pass
    i2c_bus.writeto(tca_addr, bytes([ch_mask]))
    i2c_bus.unlock()
    time.sleep(0.05)


chswitch(chan0)
lsensor = adafruit_vl53l1x.VL53L1X(i2c_bus)

lsensor.distance_mode = 2
lsensor.timing_budget = 100

lsensor.start_ranging()

chswitch(chan3)
rsensor = adafruit_vl53l1x.VL53L1X(i2c_bus)
rsensor.distance_mode = 2

rsensor.timing_budget = 100

rsensor.start_ranging()

p_h = 11
p_w = 2
b_s = 4
max_s = 5

leftp = 22
rightp = 13
bx, by = 32, 16

bdx, bdy = 1, 1
score_l = 0
score_r = 0

game_on = True

bm = displayio.Bitmap(64, 32, 4)

pal = displayio.Palette(4)
pal[0] = 0x000000
pal[1] = 0xFFFFFF
pal[2] = 0xFF0000
pal[3] = 0x00FF00

tg = displayio.TileGrid(bm, pixel_shader=pal)
game_grp = displayio.Group()
game_grp.append(tg)

font = terminalio.FONT

score_l_label = label.Label(font, text="0", color=0x0000FF, scale=1)
score_l_label.anchor_point = (0.5, 0.5)

score_l_label.anchored_position = (21, 8)

score_r_label = label.Label(font, text="0", color=0x0000FF, scale=1)

score_r_label.anchor_point = (0.5, 0.5)
score_r_label.anchored_position = (43, 8)

game_grp.append(score_l_label)
game_grp.append(score_r_label)


def draw_p(x, y):
    for boo in range(p_w):
        for cubs in range(p_h):
            if 0 <= x + boo < 64 and 0 <= y + cubs < 32:
                bm[x + boo, y + cubs] = 1


def draw_b(x, y):
    for i in range(b_s):
        for zzz in range(b_s):
            if 0 <= x + i < 64 and 0 <= y + zzz < 32:
                bm[x + i, y + zzz] = 3


def clear():
    for go in range(64):
        for cardinals in range(32):
            bm[go, cardinals] = 0


def reset_b():
    return 32, 16, random.choice([-1, 1]), random.choice([-1, 1])


def game_over(win):
    clear()
    text = f"{win.upper()} WINS"
    fnt = terminalio.FONT

    ta = label.Label(fnt, text=text, scale=1)
    ta.anchor_point = (0.5, 0.5)

    ta.anchored_position = (disp.width // 2, disp.height // 2)
    disp.root_group = displayio.Group()

    disp.root_group.append(ta)
    disp.refresh()

    time.sleep(3)

    disp.root_group = game_grp
    return False


disp.root_group = game_grp

while True:
    if game_on:
        clear()

        chswitch(chan0)
        if lsensor.data_ready:
            dist_l = lsensor.distance
            lsensor.clear_interrupt()

            if dist_l is not None and dist_l < 15:
                leftp = max(0, leftp - 1)

            else:
                leftp = min(22, leftp + 1)

        chswitch(chan3)
        if rsensor.data_ready:
            dist_r = rsensor.distance
            rsensor.clear_interrupt()

            if dist_r is not None and dist_r < 15:
                rightp = max(0, rightp - 1)
            else:
                rightp = min(22, rightp + 1)

        bx += bdx
        by += bdy

        if by <= 0 or by >= 30:
            bdy *= -1

        if (bx <= p_w and
                leftp <= by < leftp + p_h):
            bdx *= -1
        elif (bx >= 64 - p_w - b_s and
              rightp <= by < rightp + p_h):
            bdx *= -1

        if bx < 0:
            score_r += 1
            if score_r >= max_s:
                game_on = game_over("right")
            bx, by, bdx, bdy = reset_b()

        elif bx > 62:
            score_l += 1
            if score_l >= max_s:
                game_on = game_over("left")
            bx, by, bdx, bdy = reset_b()

        draw_p(0, leftp)
        draw_p(62, rightp)
        draw_b(bx, by)

        score_l_label.text = str(score_l)

        score_r_label.text = str(score_r)

        disp.refresh()
        time.sleep(0.01)

    else:
        score_l = 0
        score_r = 0
        leftp = 22
        rightp = 13
        bx, by, bdx, bdy = reset_b()
        game_on = True


        time.sleep(0.5)
