# CoreS3-Lite / UIFlow 2.0: 教材ステップ12の照合用
import M5
import time


M5.begin()
lcd = M5.Lcd
lcd.setRotation(1)
BG = 0x101820
if (lcd.width(), lcd.height()) != (320, 240):
    raise RuntimeError("Expected 320x240; check rotation")
canvas = lcd.newCanvas(320, 240, 16, True)
mode = None
lcd.fillScreen(BG)
lcd.setTextColor(0xFFFFFF, BG)
lcd.setTextSize(1)
lcd.drawString("Choose control", 8, 40)
lcd.fillRect(20, 100, 130, 60, 0x285880)
lcd.fillRect(170, 100, 130, 60, 0x285880)
lcd.setTextColor(0xFFFFFF, 0x285880)
lcd.drawString("TOUCH", 55, 125)
lcd.drawString("TILT", 215, 125)
while mode is None:
    M5.update()
    if M5.Touch.getCount() > 0:
        tx = M5.Touch.getX()
        ty = M5.Touch.getY()
        if 100 <= ty < 160:
            if 20 <= tx < 150:
                mode = "touch"
            elif 170 <= tx < 300:
                mode = "tilt"
    time.sleep_ms(20)

# 選択時のタッチを、ゲーム側に持ち越さない
while True:
    M5.update()
    if M5.Touch.getCount() == 0:
        break
    time.sleep_ms(20)


TILT_AXIS = 0  # 0=X、1=Y。持ち方に合わせる
TILT_SIGN = 1  # 左右が逆なら-1
neutral = 0.0
filtered = 0.0
if mode == "tilt":
    lcd.fillScreen(BG)
    lcd.setTextColor(0xFFFFFF, BG)
    lcd.drawString("Hold still...", 8, 100)
    time.sleep_ms(300)
    total = 0
    for _ in range(40):
        M5.update()
        total += M5.Imu.getAccel()[TILT_AXIS]
        time.sleep_ms(10)
    neutral = total / 40

WHITE = 0xFFFFFF
px = 128
paddle_y = 198
paddle_w = 64
ball_x = 160
ball_y = 150
radius = 4
colors = (0xFF7868, 0xFFC857, 0x5AD6C7)
bricks = []
for row in range(3):
    for col in range(6):
        bricks.append([12 + col * 50, 40 + row * 20, colors[row]])
score = 0


vx = 70
vy = -110
last = time.ticks_ms()

restart = True
was_down = False

while True:
    if restart:
        px = (320 - paddle_w) / 2
        ball_x = px + paddle_w / 2
        ball_y = paddle_y - radius - 1
        vx, vy = 70, -110
        bricks = []
        for row in range(3):
            for col in range(6):
                bricks.append([12 + col * 50, 40 + row * 20, colors[row]])
        score = 0
        lives = 3
        state = "ready"
        restart = False
    now = time.ticks_ms()
    dt = max(0, min(0.05, time.ticks_diff(now, last) / 1000))
    last = now
    # 入力：下部の帯に触れたときだけパドルを動かす
    M5.update()
    down = M5.Touch.getCount() > 0
    tx = M5.Touch.getX() if down else 0
    ty = M5.Touch.getY() if down else 0
    pressed = down and not was_down
    was_down = down
    if pressed and 25 <= ty < paddle_y:
        if state == "ready":
            state = "play"
        elif state in ("clear", "over"):
            restart = True
            continue

    if state in ("ready", "play"):
        if mode == "touch":
            if down and ty >= 212:
                px = tx - paddle_w / 2
        else:
            value = (M5.Imu.getAccel()[TILT_AXIS] - neutral) * TILT_SIGN
            filtered = 0.8 * filtered + 0.2 * value
            tilt = 0 if abs(filtered) < 0.04 else filtered
            px += tilt * 650 * dt
        px = max(0, min(320 - paddle_w, px))
    if state == "ready":
        ball_x = px + paddle_w / 2
        ball_y = paddle_y - radius - 1

    # 移動
    if state == "play":
        # 移動：1回の移動量を2px以下に分ける
        steps = max(1, int(max(abs(vx), abs(vy)) * dt / 2) + 1)
        for _ in range(steps):
            old_x, old_y = ball_x, ball_y
            ball_x += vx * dt / steps
            ball_y += vy * dt / steps
            if ball_x < radius:
                ball_x, vx = radius, abs(vx)
            elif ball_x > 320 - radius:
                ball_x, vx = 320 - radius, -abs(vx)
            if ball_y < 25 + radius:
                ball_y, vy = 25 + radius, abs(vy)

            for i, (bx, by, color) in enumerate(bricks):
                if (ball_x + radius > bx and ball_x - radius < bx + 46
                        and ball_y + radius > by and ball_y - radius < by + 14):
                    if old_y + radius <= by:
                        ball_y, vy = by - radius, -abs(vy)
                    elif old_y - radius >= by + 14:
                        ball_y, vy = by + 14 + radius, abs(vy)
                    elif old_x < bx:
                        ball_x, vx = bx - radius, -abs(vx)
                    else:
                        ball_x, vx = bx + 46 + radius, abs(vx)
                    del bricks[i]
                    score += 10
                    break

            if not bricks:
                state = "clear"
                break

            if (vy > 0 and old_y + radius <= paddle_y <= ball_y + radius
                    and ball_x + radius >= px
                    and ball_x - radius <= px + paddle_w):
                ball_y, vy = paddle_y - radius, -abs(vy)

            if ball_y - radius > 240:
                lives -= 1
                state = "over" if lives == 0 else "ready"
                if state == "ready":
                    ball_x = px + paddle_w / 2
                    ball_y = paddle_y - radius - 1
                    vx, vy = 70, -110
                break

    # 描画：消す → 部品を描く → まとめて表示
    canvas.fillRect(0, 0, 320, 240, BG)
    canvas.setTextColor(WHITE, BG)
    canvas.setTextSize(1)
    canvas.drawString("Score:%d Lives:%d %s" % (score, lives, mode.upper()), 8, 8)
    for bx, by, color in bricks:
        canvas.fillRect(bx, by, 46, 14, color)
    canvas.fillRect(int(px), paddle_y, paddle_w, 8, 0x7CC7FF)
    canvas.fillCircle(int(ball_x), int(ball_y), radius, WHITE)
    canvas.fillRect(0, 212, 320, 28, 0x253848)
    canvas.setTextColor(WHITE, 0x253848)
    hint = "SLIDE HERE" if mode == "touch" else "TILT LEFT / RIGHT"
    canvas.drawString(hint, 8, 220)
    if state != "play":
        if state == "ready":
            message = "READY: tap field to start"
        elif state == "clear":
            message = "CLEAR! Tap field to retry"
        else:
            message = "GAME OVER: tap field to retry"
        canvas.fillRect(4, 112, 312, 28, BG)
        canvas.setTextColor(WHITE, BG)
        canvas.drawString(message, 8, 122)
    canvas.push(0, 0)
    time.sleep_ms(33)
