# 4 digit entry code (40% - 49%)
# 4 button input, 4 LED output indication (any colour), Combination Code comparison, Green
# LED (code correct), Red LED (code incorrect), system lock, output message to serial monitor.

import time
import machine as m

# Setup LEDs
green_led = m.Pin(15, m.Pin.OUT)  # Initialize Pin 15 as an output for the green LED (indicates correct code).
red_led = m.Pin(14, m.Pin.OUT)    # Initialize Pin 14 as an output for the red LED (indicates incorrect code).

# Setup buttons
# Create a list of button objects, each initialized as an input with a pull-up resistor
buttons = [
    m.Pin(8, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 8 assigned to Button 0 with pull-up active
    m.Pin(9, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 9 assigned to Button 1 with pull-up active
    m.Pin(10, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 10 assigned to Button 2 with pull-up active
    m.Pin(11, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 11 assigned to Button 3 with pull-up active
    m.Pin(12, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 12 assigned to Button 4 with pull-up active
    m.Pin(13, m.Pin.IN, m.Pin.PULL_UP),  # GPIO Pin 13 assigned to Button 5 with pull-up active
]

# Setup other LEDs to indicate button press
# These LEDs will light up corresponding to the button being pressed
other_leds = [
    m.Pin(2, m.Pin.OUT),  # LED for Button 0
    m.Pin(3, m.Pin.OUT),  # LED for Button 1
    m.Pin(4, m.Pin.OUT),  # LED for Button 2
    m.Pin(5, m.Pin.OUT),  # LED for Button 3
    m.Pin(6, m.Pin.OUT),  # LED for Button 4
    m.Pin(7, m.Pin.OUT),  # LED for Button 5
]

# Correct combination (e.g., 1, 2, 3, 4)
correct_code = [0, 1, 2, 3]  # This is the correct sequence of button presses
input_code = []  # List to store the user's button presses
attempts = 0  # Track the number of failed attempts
max_attempts = 3  # Maximum number of failed attempts before locking the system
lock_duration = 5


def lock_system(lock_duration):
    """Lock the system for a defined duration."""
    print("System locked. Please wait...")  # Inform the user that the system is locked
    for _ in range(lock_duration):  # Loop for the specified lock duration
        red_led.toggle()  # Blink the red LED to indicate the system is locked
        time.sleep(1)  # Wait for 1 second between toggles
    red_led.off()  # Ensure the red LED is turned off after the lock period ends

def reset_leds():
    """Turn off all LEDs."""
    for led in other_leds:  # Iterate through all LEDs in the `other_leds` list
        led.off()  # Turn off each LED
    green_led.off()  # Turn off the green LED
    red_led.off()  # Turn off the red LED

def indicate_attempt(status):
    """Indicate attempt result with LEDs."""
    if status == "success":  # If the attempt is successful
        green_led.on()  # Turn on the green LED to indicate success
        time.sleep(1)  # Keep the green LED on for 1 second
        green_led.off()  # Turn off the green LED after the delay
    elif status == "failure":  # If the attempt fails
        red_led.on()  # Turn on the red LED to indicate failure
        time.sleep(1)  # Keep the red LED on for 1 second
        red_led.off()  # Turn off the red LED after the delay

def check_code():
    """Check if the entered code is correct."""
    global attempts, input_code  # Declare attempts and input_code as global to modify them

    if input_code == correct_code:  # If the input code matches the correct code
        indicate_attempt("success")
        print("Code correct!")  # Output a message to indicate success
        green_led.on()  # Turn on the green LED to signal success
        time.sleep(2)  # Wait for 2 seconds
        green_led.off()  # Turn off the green LED after the delay
        input_code.clear()  # Clear the input code for the next attempt
        indicate_attempt("success")
        attempts = 0  # Reset the number of attempts
    else:  # If the input code does not match the correct code
        print("Code incorrect!")  # Output a message to indicate failure
        red_led.on()  # Turn on the red LED to signal failure
        time.sleep(2)  # Wait for 2 seconds
        red_led.off()  # Turn off the red LED after the delay
        input_code.clear()  # Clear the input code to allow for a new attempt
        attempts += 1  # Increment the number of attempts
        indicate_attempt("failure")
        if attempts >= max_attempts:  # If the maximum number of attempts is reached
            lock_system(5)  # Simulate a system lock for 5 seconds
            attempts = 0  # Reset the attempts after lock period

def read_buttons():
    """Read the buttons and build the input code."""
    global input_code  # Declare input_code as global to modify it

    input_code = []  # Reset input code
    print("System locked, enter code to unlock:")

    while len(input_code) < len(correct_code):
        for i, button in enumerate(buttons):
            if not button.value():  # Button pressed
                input_code.append(i)  # Record button index
                other_leds[i].on() # Light up corresponding LED
                print(f"Button {i} pressed.")
                time.sleep(0.3)  # Debounce delay
                other_leds[i].off()  # Turn off LED
    return input_code


reset_leds() # Call the reset_leds() function to reset all LEDs
read_buttons()  # Continuously check for button presses and build the input code
check_code()  # Check if the entered code is correct
$abcdeabcde151015202530354045505560fghijfghij