from machine import Pin  # Importa la clase Pin de la librería machine para interactuar con los pines GPIO de la placa.
import uasyncio as asyncio  # Importa la librería asyncio para usar programación asíncrona con corutinas.

# Configuración de pines para los LEDs del Semáforo 1
led_rojo_1 = Pin(15, Pin.OUT)  # Configura el pin 15 como salida para el LED rojo del semáforo 1.
led_amarillo_1 = Pin(14, Pin.OUT)  # Configura el pin 14 como salida para el LED amarillo del semáforo 1.
led_verde_1 = Pin(13, Pin.OUT)  # Configura el pin 13 como salida para el LED verde del semáforo 1.
led_az_1 = Pin(12, Pin.OUT)  # Configura el pin 12 como salida para el LED azul del semáforo 1.

# Configuración de pines para los LEDs del Semáforo 2
led_rojo_2 = Pin(11, Pin.OUT)  # Configura el pin 11 como salida para el LED rojo del semáforo 2.
led_amarillo_2 = Pin(10, Pin.OUT)  # Configura el pin 10 como salida para el LED amarillo del semáforo 2.
led_verde_2 = Pin(9, Pin.OUT)  # Configura el pin 9 como salida para el LED verde del semáforo 2.
led_az_2 = Pin(8, Pin.OUT)  # Configura el pin 8 como salida para el LED azul del semáforo 2.

# Configuración de pines para semáforo peatonal
led_rojoPet = Pin(16, Pin.OUT)  # Configura el pin 16 como salida para el LED rojo del semáforo peatonal.
led_verdPet = Pin(17, Pin.OUT)  # Configura el pin 17 como salida para el LED verde del semáforo peatonal.

#buzzer.duty_u16(32768)  # Ciclo de trabajo al 50%

# Configuración del pin del botón
boton_pin = Pin(22, Pin.IN, Pin.PULL_UP)  # Configura el pin 22 como entrada con resistencia pull-up para el botón.

# Configuración del pin para el buzzer
buzzer = Pin(28, Pin.OUT)  # Configura el pin 28 como salida para el buzzer.

# Variable global para manejar la interrupción
interrupcion = False  # Define una variable global para gestionar la interrupción del botón.

def manejar_interrupcion(pin):
    """
    Callback para manejar la interrupción del botón.
    Esta función se ejecuta cuando se detecta que el botón ha sido presionado.
    """
    global interrupcion  # Usa la variable global 'interrupcion'
    interrupcion = True  # Activa la interrupción (se cambia a True cuando el botón es presionado)

async def detener_todo():
    """
    Apaga todos los LEDs excepto el verde peatonal y mantiene este estado por 7 segundos.
    También activa el buzzer durante un breve periodo.
    """
    leds = [led_rojo_1, led_amarillo_1, led_verde_1, led_az_1,
            led_rojo_2, led_amarillo_2, led_verde_2, led_az_2, led_rojoPet]
    for led in leds:  # Apaga todos los LEDs
        led.value(0)

    led_rojo_1.value(1)  # Enciende los LEDs rojos de ambos semáforos y el rojo peatonal.
    led_rojo_2.value(1)
    led_verdPet.value(1)
    buzzer.value(1)  # Activa el buzzer.
    await asyncio.sleep(2)  # Espera 2 segundos.

    loa = 0.8  # Define el tiempo inicial del parpadeo.
    for _ in range(8):  # Parpadeo de 8 ciclos con reducción progresiva del retardo
        buzzer.value(0)  # Apaga el buzzer y el LED verde peatonal.
        led_verdPet.value(0)
        await asyncio.sleep(loa)  # Espera según el retardo actual.
        buzzer.value(1)  # Enciende el buzzer y el LED verde peatonal.
        led_verdPet.value(1)
        await asyncio.sleep(loa)  # Espera según el retardo actual.
        loa -= 0.1  # Reduce el tiempo de espera para acelerar el parpadeo.

    print("Interrupción activa: Solo LEDs rojos de semáforos y verde peatonal encendidos.")
    #await asyncio.sleep(1)

    buzzer.value(0)  # Apaga el buzzer y el LED verde peatonal.
    led_verdPet.value(0)
    led_rojo_1.value(0)  # Apaga los LEDs rojos de los semáforos.
    led_rojo_2.value(0)
    print("Interrupción terminada, reanudando secuencia.")

async def secuencia_semaforo_1():
    """
    Secuencia de luces para el semáforo 1. 
    Define el ciclo de luces: Rojo, Amarillo, Verde con parpadeo.
    """
    while True:  # Un bucle infinito que repetirá la secuencia de luces del semáforo.
        # RED AND BLUE 12seg
        buzzer.value(0)  # Apaga el buzzer.
        led_rojoPet.value(1)  # Enciende el LED rojo peatonal.
        led_rojo_1.value(1)  # Enciende el LED rojo del semáforo 1.
        led_amarillo_1.value(0)  # Apaga el LED amarillo del semáforo 1.
        led_verde_1.value(0)  # Apaga el LED verde del semáforo 1.
        led_az_1.value(0)  # Enciende el LED azul del semáforo 1.
        print("Semáforo 1: azul y rojo")
        await asyncio.sleep(9)  # Espera 6 segundos.
        
        led_az_1.value(1)  # Apaga el LED azul.
        print("Semáforo 1: ROJO")
        await asyncio.sleep(3)  # Espera 4 segundos.

        # GREEN
        led_rojo_1.value(0)
        led_az_1.value(0)  # Apaga el LED azul.
        led_amarillo_1.value(0)  # Apaga el LED amarillo.
        led_verde_1.value(1)  # Enciende el LED verde del semáforo 1.
        print("Semáforo 1: VERDE")
        await asyncio.sleep(3)  # Espera 4 segundos.

        # Parpadeo acelerado después de 4 segundos
        delay = 0.5  # Define el tiempo de retardo para el parpadeo.
        for _ in range(6):  # Parpadeo de 6 ciclos con reducción progresiva del retardo
            led_verde_1.value(0)  # Apaga el LED verde.
            await asyncio.sleep(delay)
            led_verde_1.value(1)  # Enciende el LED verde.
            await asyncio.sleep(delay)
            delay -= 0.1  # Reduce el tiempo de espera para acelerar el parpadeo.

        print("Semáforo 1: VERDE") # 7 segundos
        
        # YELLOW
        led_rojo_1.value(0)  # Apaga el LED rojo.
        led_verde_1.value(0)  # Apaga el LED verde.
        led_az_1.value(0)  # Apaga el LED azul.
        led_amarillo_1.value(1)  # Enciende el LED amarillo.
        print("Semáforo 1: AMARILLO")
        await asyncio.sleep(2)  # Espera 10 segundos.

async def secuencia_semaforo_2():
    """
    Secuencia de luces para el semáforo 2. 
    Define el ciclo de luces: Rojo, Amarillo, Verde con parpadeo.
    """
    while True:  # Un bucle infinito que repetirá la secuencia de luces del semáforo.
        buzzer.value(0)  # Apaga el buzzer.
        led_rojo_2.value(0)  # Apaga el LED rojo del semáforo 2.
        led_amarillo_2.value(0)  # Apaga el LED amarillo del semáforo 2.
        led_verde_2.value(1)  # Enciende el LED verde del semáforo 2.
        await asyncio.sleep(4) 
        print("Semáforo 2: VERDE")

        # Parpadeo acelerado después de 4 segundos
        delay = 0.5  # Define el tiempo de retardo para el parpadeo.
        for _ in range(6):  # Parpadeo de 6 ciclos con reducción progresiva del retardo
            led_verde_2.value(0)  # Apaga el LED verde.
            await asyncio.sleep(delay)
            led_verde_2.value(1)  # Enciende el LED verde.
            await asyncio.sleep(delay)
            delay -= 0.1  # Reduce el tiempo de espera para acelerar el parpadeo.

        print("Semáforo 2: VERDE")

        led_verde_2.value(0)  # Apaga el LED verde.
        led_amarillo_2.value(1)  # Enciende el LED amarillo del semáforo 2.
        print("Semáforo 2: AMARILLO")
        await asyncio.sleep(2)  # Espera 10 segundos.

        led_amarillo_2.value(0)  # Apaga el LED amarillo.
        led_rojo_2.value(1)  # Enciende el LED rojo del semáforo 2.
        print("Semáforo 2: azul y rojo")
        await asyncio.sleep(11)  # Espera 3 segundos.
        

async def main():
    """
    Función principal que ejecuta las tareas asíncronas para los semáforos y maneja la interrupción del botón.
    """
    global interrupcion  # Usa la variable global 'interrupcion'

    task1 = asyncio.create_task(secuencia_semaforo_1())  # Crea una tarea para ejecutar la secuencia del semáforo 1.
    task2 = asyncio.create_task(secuencia_semaforo_2())  # Crea una tarea para ejecutar la secuencia del semáforo 2.

    while True:  # Bucle infinito para revisar la interrupción.
        if interrupcion:  # Si la interrupción está activa (botón presionado)
            print("Interrupción detectada, deteniendo semáforos.")
            task1.cancel()  # Cancela la tarea del semáforo 1.
            task2.cancel()  # Cancela la tarea del semáforo 2.
            await detener_todo()  # Detiene todo y maneja los LEDs y el buzzer durante la interrupción.
            task1 = asyncio.create_task(secuencia_semaforo_1())  # Reinicia la tarea del semáforo 1.
            task2 = asyncio.create_task(secuencia_semaforo_2())  # Reinicia la tarea del semáforo 2.
            interrupcion = False  # Resetea la interrupción a False.

        await asyncio.sleep(0.1)  # Pausa de 0.1 segundos antes de la siguiente iteración del bucle.

# Configura el botón para que dispare una interrupción cuando se presione (transición de HIGH a LOW).
boton_pin.irq(trigger=Pin.IRQ_FALLING, handler=manejar_interrupcion)

# Ejecuta la función principal en el ciclo de eventos de asyncio.
try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Programa detenido")  # Captura la interrupción del teclado y detiene el programa.