# --- Import necessary libraries ---
from mpu6050 import mpu6050# Library for MPU6050 accelerometer/gyroscope sensor
import time# Time functions
import asyncio# For potential asynchronous tasks (unused here)
import MySQLdb# MySQL database connector
import RPi.GPIO as GPIO# Raspberry Pi GPIO control library

# --- GPIO Setup ---
GPIO.setmode(GPIO.BCM)# Use Broadcom pin numbering

# Define GPIO pins for RGB LED
redPin = 18
greenPin = 14
bluePin = 15

# Set LED pins as output
GPIO.setup(redPin, GPIO.OUT)
GPIO.setup(greenPin, GPIO.OUT)
GPIO.setup(bluePin, GPIO.OUT)

# Initialize PWM for RGB pins at 1kHz
RED = GPIO.PWM(redPin, 1000)
GREEN = GPIO.PWM(greenPin, 1000)
BLUE = GPIO.PWM(bluePin, 1000)

# Start PWM with 0% duty cycle (LEDs off)
RED.start(0)
GREEN.start(0)
BLUE.start(0)

# Setup push button input on GPIO pin 16 with internal pull-up resistor
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# --- Configuration and State Variables ---
cycletime = 1  # Delay between sensor reads (in seconds)
canStore = {"Store": False}  # Flag to allow data storage
canCollect = {"Collect": False}  # Flag to allow data collection
caseVariable = {"Case": "None"}  # Tracks LED/data collection state

# --- Sensor and Timer Initialization ---
mpu = mpu6050(0x68)  # Instantiate MPU6050 with I2C address

start_time = None
elapsed_time = 0
running = False

# --- Stopwatch-style Timer Functions ---
def start():
    global start_time, running
    if not running:
        start_time = time.time()
        running = True
print(time.time())

def stop():
    global elapsed_time, running
    if running:
        elapsed_time += time.time() - start_time
        running = False

def reset():
    global start_time, elapsed_time, running
    start_time = None
    elapsed_time = 0
    running = False

def get_elapsed():
    if running:
        return time.time() - start_time + elapsed_time
    else:
        return elapsed_time

print(f"Total elapsed time: {get_elapsed():.2f} seconds")

# --- Utility function to remap a value between ranges ---
def _map(x, in_min, in_max, out_min, out_max):
    return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)

# --- Main Logic Function ---
def main():
    # Initialize button debounce variables
    last_button_time = 0
    debounce_delay = 0.2
    buttonState = GPIO.HIGH
    lastButtonState = GPIO.HIGH

    ms = 0  # Milliseconds elapsed
canStore["Store"] = False
    canCount = False
    data = []  # Buffer for collected sensor data
    lastTime = time.time()

    # Start with RED LED on
RED.ChangeDutyCycle(_map(255, 0, 255, 0, 100))

    # Connect to MySQL database
    connection = MySQLdb.connect(
host='127.0.0.1',
        db='gyrodb',
user='sysadmin',
passwd='sysadmin'
    )
    cursor = connection.cursor()

    # --- Main Loop ---
    while True:
        current_time = time.time()
currentButtonState = GPIO.input(16)

        # Query latest cycle ID
cursor.execute("SELECT cID FROM gyrocycle ORDER BY cID DESC LIMIT 1")
        latest_id = cursor.fetchone()
connection.commit  # Note: Missing parentheses!

        # --- Button state change detection (edge-triggered) ---
        if currentButtonState == GPIO.HIGH and lastButtonState == GPIO.LOW:
            if (current_time - last_button_time) > debounce_delay:
last_button_time = current_time
print("Button Released")

                if caseVariable["Case"] == "None":
                    # Transition: RED → BLUE
BLUE.ChangeDutyCycle(_map(255, 0, 255, 0, 100))
RED.ChangeDutyCycle(0)
caseVariable["Case"] = "WriteFirst"
print("Red to Blue")
stop()
reset()
                else:
                    # Transition: BLUE → RED
BLUE.ChangeDutyCycle(0)
RED.ChangeDutyCycle(_map(255, 0, 255, 0, 100))
caseVariable["Case"] = "None"
canStore["Store"] = False
print("Blue to Red")

                    # Update session duration in database
cursor.execute("""
UPDATE gyrocycle 
SET cLengthSec = %s
WHERE cID = (SELECT MAX(cID) FROM gyrocycle);
""", (ms*1000,))
connection.commit()
                    ms = 0

        # Update button state tracker
lastButtonState = currentButtonState

        # --- Sensor data logging loop ---
        thisTime = time.time()
        if canStore["Store"]:
cursor.execute("SELECT cID FROM gyrocycle ORDER BY cID DESC LIMIT 1")
            latest_id = cursor.fetchone()
            data_id = latest_id[0]

            gyro = mpu.get_gyro_data()
acceleration = mpu.get_accel_data()

            # Safety fallback
            if latest_id == None:
data_id = 0

            ms = get_elapsed()
data.append((data_id, ms*1000, gyro['x'], gyro['y'], gyro['z'],
acceleration['x'], acceleration['y'], acceleration['z']))
canStore["Store"] = False
print("Appended")
print(data)

        # --- Case-based operation state machine ---
        match caseVariable["Case"]:
            case "WriteFirst":
start()
canCount = True
print("First case")
cursor.execute("INSERT INTO gyrodb.gyrocycle (cLengthSec) VALUES (%s);", (ms,))
connection.commit()
caseVariable["Case"] = "Store"

            case "Store":
RED.ChangeDutyCycle(_map(0, 0, 255, 0, 100))  # Fade RED
                if thisTime - lastTime > cycletime:
                    ms = get_elapsed()
canStore["Store"] = True
canCollect["Collect"] = True
print("Collected")
caseVariable["Case"] = "Collect"

            case "Collect":
                if canCollect["Collect"]:
query = """
INSERT INTO gyrodb.gyrodata 
(cID, cMS, cGX, cGY, cGZ, cAX, cAY, cAZ)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
"""
cursor.executemany(query, data)
print("executed")
connection.commit()
print(ms*1000)
lastTime = thisTime
canCollect["Collect"] = False
data.clear()
caseVariable["Case"] = "Store"

# --- Run the main function ---
main()
