import time, board, pwmio, neopixel, busio
from adafruit_apds9960.apds9960 import APDS9960

# Set Up Neopixel Strip
pin = board.GP16                       # Lights wired to GP16 
number_of_pixels = 10
brightness = 0.5
pixels = neopixel.NeoPixel(pin, number_of_pixels, brightness = brightness)

# Test Out Your Lights
# print("Testing out the Lights")
# pixels.fill((0, 0, 255))
# while True:
#     pass

# Set Up Speaker
audio = board.GP0                        # Audio wired to GP0
volume = 0.05
buzzer = pwmio.PWMOut(
    audio,
    duty_cycle = 0,
    frequency = 440,
    variable_frequency = True
)


def play_tone(freq, duration):
    global volume
    if freq <= 0:
        time.sleep(duration)
        return
    buzzer.frequency = freq
    buzzer.duty_cycle = int(2**15 * volume)
    time.sleep(duration)
    buzzer.duty_cycle = 0      # Off

def clear_pixels():
    pixels.fill((0, 0, 0))
    pixels.show()

# Set Up APDS-9960
i2c = busio.I2C(board.GP5, board.GP4)               # Pico: SCL = GP5, SDA = GP4
sensor = APDS9960(i2c)
sensor.enable_color = True
time.sleep(0.2)

# Feedback
def speak(label):
    # print(label)
    tones = {
        "light": 800,
        "dark": 200,
        "high contrast": 600,
        "low contrast": 300,
        "red-ish": 660,
        "green-ish": 550,
        "blue-ish": 440,
        "yellow-ish": 770,
        "neutral": 500
    }
    play_tone(tones.get(label, 500), 0.2)

# "Light" vs "Dark"
def brightness_pattern(brightness_label):
    clear_pixels()

    if brightness_label == "light":
        # Fast white flashes
        for _ in range(3):
            pixels.brightness = 0.7
            pixels.fill((255, 255, 255))
            pixels.show()
            time.sleep(0.1)
            clear_pixels()
            time.sleep(0.1)
        pixels.brightness = brightness

    else:  # "Dark"
        # Slow soft blue breathing
        for b in (0.05, 0.2, 0.05):
            pixels.brightness = b
            pixels.fill((0, 0, 80))
            pixels.show()
            time.sleep(0.25)
        pixels.brightness = brightness
        clear_pixels()

# "High Contrast" vs "Low Contrast"
def contrast_pattern(contrast_label):
    clear_pixels()

    if contrast_label == "high contrast":
        # Alternating bright/dark
        for _ in range(3):
            for i in range(number_of_pixels):
                pixels[i] = (255, 255, 255) if i % 2 == 0 else (0, 0, 0)
            pixels.show()
            time.sleep(0.12)
            clear_pixels()
            time.sleep(0.12)

    else:  # "Low Contrast"
        # Soft glow
        pixels.fill((40, 40, 40))
        pixels.show()
        time.sleep(0.6)
        clear_pixels()

# Show Colour
def color_family_pattern(color_family):
    color_map = {
        "red-ish": (255, 0, 0),
        "green-ish": (0, 180, 0),
        "blue-ish": (0, 0, 255),
        "yellow-ish": (255, 200, 0),
        "neutral": (80, 80, 80)
    }
    color = color_map.get(color_family, (80, 80, 80))

    pixels.brightness = brightness
    pixels.fill(color)
    pixels.show()
    time.sleep(0.5)
    clear_pixels()


while True:
    r, g, b, c = sensor.color_data

    # Guard Statement for Bad Reads
    if r == 0 and g == 0 and b == 0 and c == 0:
        print("No color data yet...")
        time.sleep(0.2)
        continue

    # Brightness
    brightness = c

    if brightness > 3000:                     # Adjust as needed
        brightness_label = "light"
    else:
        brightness_label = "dark"

    # High or Low Contrast
    contrast = max(r, g, b) - min(r, g, b)

    if contrast > 1000:                      # Adjust as needed
        contrast_label = "high contrast"
    else:
        contrast_label = "low contrast"

    # Colour Group
    # If the sensor hasn't stabilized or returns zeros, default to neutral
    if (r + g) == 0:
        rg_diff_ratio = 1.0   # high difference → ensures NOT yellow
    else:
        # Measure how similar R and G are (0 = identical, 1 = completely different)
        rg_diff_ratio = abs(r - g) / (r + g)
    # YELLOW: R and G both strong, similar, and much stronger than B
    if (r + g) > 2 * b and rg_diff_ratio < 0.21:
        color_family = "yellow-ish"
    # RED: R clearly dominant
    elif r > g and r > b:
        color_family = "red-ish"
    # GREEN: G clearly dominant
    elif g > r and g > b:
        color_family = "green-ish"
    # BLUE: B clearly dominant
    elif b > r and b > g:
        color_family = "blue-ish"
    else:
        color_family = "neutral"


    # Debug Print
    print("Raw:", r, g, b, c)
    print(f"Object is {brightness_label}, {contrast_label}, {color_family} colour family.\n")

    # Audio
    speak(brightness_label)
    speak(contrast_label)
    speak(color_family)

    # NeoPixel visuals
    brightness_pattern(brightness_label)
    contrast_pattern(contrast_label)
    color_family_pattern(color_family)

    time.sleep(0.5)
