import cv2
import sys
import time
import os
import subprocess
import threading

print("OpenCV version:", cv2.__version__)

# Load sounds - using afplay on macOS for M4A support
sounds_dir = "shit/sounds"
sound_files = {
    0: None,  # no sound
    1: "kick.m4a",
    2: "snare.m4a",
    3: "hihat.m4a",
    4: "bass.m4a",
    # Add more if needed for 5,6,7
}
sounds = {}
for id_val, filename in sound_files.items():
    if filename:
        path = os.path.join(sounds_dir, filename)
        if os.path.exists(path):
            sounds[id_val] = path
        else:
            print(f"Warning: Sound file {path} not found")

def play_sound(path):
    subprocess.run(['afplay', path])

# Load the dictionary
dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50)
parameters = cv2.aruco.DetectorParameters()
# Tune parameters for better detection
parameters.adaptiveThreshWinSizeMin = 3
parameters.adaptiveThreshWinSizeMax = 23
parameters.adaptiveThreshWinSizeStep = 10
parameters.minMarkerPerimeterRate = 0.03
parameters.maxMarkerPerimeterRate = 4.0
parameters.polygonalApproxAccuracyRate = 0.05
detector = cv2.aruco.ArucoDetector(dictionary, parameters)

# Open camera
cap = cv2.VideoCapture(0)
if not cap.isOpened():
    print("Cannot open camera")
    sys.exit(1)

print("Starting ArUco detection. Press 'q' to quit.")

stable_count = 0
current_sequence = None
looping = False

def loop_beat(sequence):
    global looping, current_sequence
    while looping and current_sequence == sequence:
        for id_val in sequence:
            if id_val == 0:
                print(f"Playing silence for ID {id_val}")
                time.sleep(0.3)
            elif id_val in sounds:
                print(f"Playing sound for ID {id_val}: {sounds[id_val]}")
                threading.Thread(target=play_sound, args=(sounds[id_val],)).start()
                time.sleep(0.3)
            else:
                print(f"No sound defined for ID {id_val}")
                time.sleep(0.3)
        time.sleep(0.1)  # Small gap between loops

while True:
    ret, frame = cap.read()
    if not ret:
        print("Failed to grab frame")
        break

    # Convert to grayscale
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Detect markers
    corners, ids, rejected = detector.detectMarkers(gray)

    # Draw detected markers
    if ids is not None:
        cv2.aruco.drawDetectedMarkers(frame, corners, ids)
        detected_ids = ids.flatten()
        slots = []
        for i, id_val in enumerate(detected_ids, start=1):
            slots.append(f"Slot {i}: Aruco{id_val:02d}")
        print(f"Detected: {', '.join(slots)}")

        # Check stability
        if len(detected_ids) == 8:
            sorted_ids = sorted(detected_ids)
            if sorted_ids != current_sequence:
                # New sequence detected
                current_sequence = sorted_ids
                looping = True
                print("New stable sequence detected! Starting looped beat...")
                threading.Thread(target=loop_beat, args=(sorted_ids,)).start()
            stable_count += 1
        else:
            stable_count = 0
            looping = False
            current_sequence = None
    else:
        print("No markers detected")
        stable_count = 0
        looping = False
        current_sequence = None

    # Show frame
    cv2.imshow('ArUco Detector', frame)

    # Exit on 'q'
    if cv2.waitKey(1) & 0xFF == ord('q'):
        looping = False  # Stop loop on exit
        break

cap.release()
cv2.destroyAllWindows()