import board, time, math, neopixel, digitalio, adafruit_lis3dh, busio

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

# --------------------------
# BLE SETUP
# --------------------------
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

# Name must be short – <=8 chars works
advertisement.complete_name = "CPickB"
ble.name = advertisement.complete_name
print("ble.name is", ble.name)

# --------------------------
# SWING DETECTION PARAMS
# --------------------------
SWING_THRESHOLD = 22.0   # magnitude of acceleration in m/s^2
SWING_COOLDOWN = 0.5     # seconds between registered swings

last_swing_time = 0.0
num_pixels = 40

# NeoPixel settings
pixels = neopixel.NeoPixel(board.A1, num_pixels, brightness=0.3, auto_write=False)

# Accelerometer setup
i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
int1 = digitalio.DigitalInOut(board.ACCELEROMETER_INTERRUPT)
accel = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19, int1=int1)
accel.range = adafruit_lis3dh.RANGE_8_G

print("CPickB swing sender starting up...")

def get_accel_magnitude():
    """
    Returns the magnitude of acceleration vector from the CPB's accelerometer.
    """
    x, y, z = accel.acceleration  # m/s^2
    return math.sqrt(x * x + y * y + z * z)


DIAMOND = (0, 180, 255)
DIAMOND_LOW = (0, 60, 120)
DIAMOND_HIGH = (120, 255, 255)


def do_animation(step):
    """
    Non-blocking shimmer animation.
    Call once per frame inside main loop.

    step : increasing integer counter, incremented by caller
    """
    segment_size = 10

    # Segment color layout around led strip
    segment_colors = [DIAMOND_LOW, DIAMOND, DIAMOND_HIGH, DIAMOND]

    # How many pixels the entire pattern is rotated
    offset = step % num_pixels

    # Shimmer cycle across 80 frames
    shimmer_phase = (step % 80) / 80.0
    shimmer = 0.7 + 0.3 * math.sin(2 * math.pi * shimmer_phase)

    for i in range(num_pixels):
        # Virtual index into the ring pattern (handles rotation)
        virtual_index = (i + offset) % num_pixels

        # Determine current 10-pixel segment
        segment_index = virtual_index // segment_size
        base_color = segment_colors[segment_index]

        # Apply shimmer factor
        r = int(base_color[0] * shimmer)
        g = int(base_color[1] * shimmer)
        b = int(base_color[2] * shimmer)

        pixels[i] = (r, g, b)

    pixels.show()


step = 0

while True:
    # --- ADVERTISING PHASE ---
    print("Advertising...")
    ble.start_advertising(advertisement)

    while not ble.connected:
        do_animation(step)
        step += 1
        time.sleep(0.01)

    print("Connected!")
    ble.stop_advertising()

    # --- CONNECTED PHASE ---
    while ble.connected:
        # Keep animation running while connected
        do_animation(step)
        step += 1

        # Read accelerometer
        mag = get_accel_magnitude()
        now = time.monotonic()

        # Simple swing detection
        if mag > SWING_THRESHOLD and (now - last_swing_time) > SWING_COOLDOWN:
            print("SWING detected! Sending message over BLE UART...")
            try:
                uart.write("SWING\n")  # <-- PC bridge listens for these events
            except Exception as e:
                print("Error writing to BLE UART:", e)

            last_swing_time = now

        time.sleep(0.01)

    print("Disconnected; will re-advertise.")