from machine import Pin, ADC, I2C, PWM
from utime import sleep_ms
from ssd1306 import SSD1306_I2C

led_red = PWM(Pin(15), freq=1000)
led_green = PWM(Pin(2), freq=1000)
led_blue = PWM(Pin(4), freq=1000)

led_red.duty(0)
led_green.duty(0)
led_blue.duty(0)

ancho = 128
alto = 64

datoH = ADC(Pin(32))
datoV = ADC(Pin(35))
datoH.atten(ADC.ATTN_11DB)
datoV.atten(ADC.ATTN_11DB)
boton = Pin(13, Pin.IN, Pin.PULL_UP)
i2c = I2C(0, scl=Pin(22), sda=Pin(23))
buzzer = PWM(Pin(5), duty=0)
oled = SSD1306_I2C(ancho, alto, i2c)
oled.fill(1)
pausa = 50

class Operaciones:
    def suma(a, b):
        return a + b

    def resta(a, b):
        return a - b

    def multiplicacion(a, b):
        return a * b

    def division(a, b):
        if b != 0:
            return a / b
        else:
            return "Error: División por cero"

operaciones = ["Suma", "Resta", "Multiplicar", "Dividir"]
selected_index = 0
numero1 = None
numero2 = None

def ingresar_numero(oled, mensaje):
    numero = "0" * 9
    digit_index = len(numero) - 1
    while True:
        oled.fill(0)
        oled.text(mensaje, 0, 0, 1)
        oled.text(numero, 0, 20, 1)
        
        x_pos = digit_index * 8
        y_pos = 30
        
        oled.text("^", x_pos, y_pos, 1)
        oled.show()
        
        if datoV.read() == 4095:
            digit = int(numero[digit_index])
            digit = (digit + 1) % 10
            numero = numero[:digit_index] + str(digit) + numero[digit_index + 1:]
            sleep_ms(200)
        elif datoV.read() == 0:
            digit = int(numero[digit_index])
            digit = (digit - 1) % 10
            numero = numero[:digit_index] + str(digit) + numero[digit_index + 1:]
            sleep_ms(200) 
        elif datoH.read() == 0:
            digit_index = (digit_index - 1) % len(numero)
            sleep_ms(200)
        elif datoH.read() == 4095:
            digit_index = (digit_index + 1) % len(numero)
            sleep_ms(200)
        elif boton.value() == 0:
            sleep_ms(200)
            try:
                return int(numero)
            except ValueError:
                return 0
            sleep_ms(200)

def mostrar_operaciones():
    oled.fill(0)
    oled.line(0, 15, 128, 15, 1)
    oled.text("Calculadora", 20, 5, 1)
    
    for i, operacion in enumerate(operaciones):
        if i == selected_index:
            operacion += " <"
        oled.text(operacion, 0, 20 + i * 10, 1)
    
    oled.show()

def numero_primo(n):
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

def numero_vampiro(numero):
    numero_str = str(numero)
    longitud = len(numero_str)

    if longitud % 2 != 0:
        return False

    for i in range(1, int(numero ** 0.5) + 1):
        if numero % i == 0:
            divisor1 = str(i)
            divisor2 = str(numero // i)
            if len(divisor1) == len(divisor2) == longitud // 2:
                if sorted(numero_str) == sorted(divisor1 + divisor2):
                    return True

    return False

def realizar_operacion():
    global numero1, numero2
    numero1 = ingresar_numero(oled, "Numero 1:")
    numero2 = ingresar_numero(oled, "Numero 2:")
    operacion_seleccionada = operaciones[selected_index]

    if operacion_seleccionada == "Suma":
        led_green.duty(1023)
        resultado = Operaciones.suma(numero1, numero2)
    elif operacion_seleccionada == "Resta":
        led_red.duty(1023)
        resultado = Operaciones.resta(numero1, numero2)
    elif operacion_seleccionada == "Multiplicar":
        led_red.duty(1023)
        led_green.duty(1023)
        led_blue.duty(1023)
        resultado = Operaciones.multiplicacion(numero1, numero2)
    elif operacion_seleccionada == "Dividir":
        led_blue.duty(1023)
        resultado = Operaciones.division(numero1, numero2)
    
    oled.fill(0)
    oled.text("Resultado:", 0, 20, 1)
    oled.text(f"{resultado}", 0, 30, 1)
    oled.show()
    
    if numero_primo(resultado):
        buzzer = PWM(Pin (5))
        notas = [523,1,392,1,329,1,440,493,1,466,440,1,392,622,1,784,880,1,698,784,622,523,1,587,493]
        for i in range (2):
            for i in notas:
                buzzer.freq(i)
                sleep_ms(150)
            sleep_ms(10)
            buzzer.duty(0)
    if numero_vampiro(resultado):
        buzzer = PWM(Pin (5))
        notas = [392,1,329,1,329,1,329,1,392,1,329,1,329,1,659,1,587,523,493,440,392,1,349,1,329,1,349,1,392]
        for i in range (2):
            for i in notas:
                buzzer.freq(i)
                sleep_ms(200)
            sleep_ms(10)
            buzzer.duty(0)
    sleep_ms(1000)
boton_presionado = False
boton_retraso = 200

while True:
    mostrar_operaciones()
    
    if datoV.read() == 4095:
        selected_index = (selected_index - 1) % len(operaciones)
        sleep_ms(200)
    elif datoV.read() == 0:
        selected_index = (selected_index + 1) % len(operaciones)
        sleep_ms(200)
    elif boton.value() == 0 and not boton_presionado:
        sleep_ms(boton_retraso)
        boton_presionado = True
        realizar_operacion()
    elif boton.value() == 1:
        boton_presionado = False
        sleep_ms(200)