from machine import Pin, I2C
import ssd1306
import time
import random

# ESP32 Pin assignment
i2c = I2C(0, scl=Pin(22), sda=Pin(21))

# OLED display dimensions
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

def draw_circle(oled, h, k, r, col=1, filled=False):
    """Draw a circle or filled circle on the OLED."""
    for x in range(h - r, h + r + 1):
        for y in range(k - r, k + r + 1):
            if (x - h) ** 2 + (y - k) ** 2 <= r ** 2:
                if 0 <= x < oled_width and 0 <= y < oled_height:
                    oled.pixel(x, y, col)

def draw_ellipse(oled, h, k, rx, ry, col=1):
    """Draw an ellipse on the OLED."""
    for x in range(h - rx, h + rx + 1):
        for y in range(k - ry, k + ry + 1):
            if ((x - h) ** 2) / (rx ** 2) + ((y - k) ** 2) / (ry ** 2) <= 1:
                if 0 <= x < oled_width and 0 <= y < oled_height:
                    oled.pixel(x, y, col)

def draw_eye(oled, h, k, r_outer, r_pupil, pupil_offset_x=0, pupil_offset_y=0):
    """Draw an eye with an outer circle, pupil, and an almond-shaped boundary."""
    oled.fill(0)  # Clear screen
    draw_ellipse(oled, h, k, r_outer + 5, r_outer - 2, 1)  # Almond-shaped eye
    draw_circle(oled, h, k, r_outer, 1)  # Outer circle (eye white)
    draw_circle(oled, h + pupil_offset_x, k + pupil_offset_y, r_pupil, 0, filled=True)  # Inner pupil (black)

def blink_eyes():
    """Simulate blinking by shrinking and restoring the eye."""
    for shrink in range(5, 15, 2):  # Gradually close
        oled.fill(0)
        draw_ellipse(oled, 20 + int(shrink * 2), 32, 15, shrink, 1)
        draw_ellipse(oled, 80 + int(shrink * 2), 32, 15, shrink, 1)
        draw_ellipse(oled, 20 + int(shrink * 2), 32, 5, int(shrink / 3), 0)
        draw_ellipse(oled, 80 + int(shrink * 2), 32, 5, int(shrink / 3), 0)
        oled.show()
        time.sleep(0.05)
    time.sleep(0.2)  # Closed pause
    for expand in range(13, 5, -2):  # Gradually open
        oled.fill(0)
        draw_ellipse(oled, 46 - int(26 - expand * 2), 32, 15, expand, 1)
        draw_ellipse(oled, 106 - int(26 - expand * 2), 32, 15, expand, 1)
        draw_ellipse(oled, 46 - int(26 - expand * 2), 32, 5, int(expand / 3), 0)
        draw_ellipse(oled, 106 - int(26 - expand * 2), 32, 5, int(expand / 3), 0)
        oled.show()
        time.sleep(0.05)
    time.sleep(0.2)

def animate_eyes():
    """Animate the eyes with blinking and pupil movement."""
    pupil_range = 4  # Range for pupil movement
    while True:
        pupil_x = random.randint(-pupil_range, pupil_range)
        pupil_y = random.randint(-pupil_range, pupil_range)
        draw_eye(oled, 20, 32, 15, 5, pupil_x, pupil_y)  # Left eye
        draw_eye(oled, 80, 32, 15, 5, pupil_x, pupil_y)  # Right eye
        oled.show()
        time.sleep(0.5)
        
        if random.random() < 0.2:  # 20% chance to blink
            blink_eyes()

# Start animation
while True:
    blink_eyes()
animate_eyes()