import warnings
warnings.filterwarnings("ignore", category=UserWarning)

import cv2
import numpy as np
import joblib
from collections import deque
import mediapipe.python.solutions.hands as mp_hands
import mediapipe.python.solutions.drawing_utils as mp_draw

model = joblib.load("gesture_model.joblib")

hands = mp_hands.Hands(max_num_hands=1, model_complexity=0,
    min_detection_confidence=0.6, min_tracking_confidence=0.5)

def normalize(lm):
    pts = np.array([[p.x, p.y, p.z] for p in lm])
    pts = pts - pts[0]
    scale = np.linalg.norm(pts[9])
    pts = pts / (scale + 1e-6)
    return pts.flatten()

COMMANDS = {
    "OPEN_PALM": "STOP",
    "FIST": "SIT",
    "THUMBS_UP": "STAND",
    "POINTING": "FORWARD",
    "PEACE": "BACKWARD",
}

CONF_THRESHOLD = 0.6
HOLD_FRAMES = 15
prob_window = deque(maxlen=7)

last_gesture = None
stable_count = 0
fired = None

cap = cv2.VideoCapture(0)
print("Running... q to quit")

while True:
    ret, frame = cap.read()
    if not ret:
        break
    frame = cv2.flip(frame, 1)
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = hands.process(rgb)

    gesture = "no hand"
    conf = 0.0
    if results.multi_hand_landmarks:
        h = results.multi_hand_landmarks[0]
        mp_draw.draw_landmarks(frame, h, mp_hands.HAND_CONNECTIONS)
        feat = normalize(h.landmark).reshape(1, -1)
        probs = model.predict_proba(feat)[0]
        prob_window.append(probs)
        avg = np.mean(prob_window, axis=0)
        i = int(np.argmax(avg))
        conf = float(avg[i])
        gesture = model.classes_[i] if conf >= CONF_THRESHOLD else "UNSURE"
    else:
        prob_window.clear()

    # debounce
    if gesture == last_gesture:
        stable_count += 1
    else:
        stable_count = 0
        last_gesture = gesture
        fired = None

    # fire command once when stable
    if stable_count == HOLD_FRAMES and gesture in COMMANDS and fired != gesture:
        print("CMD:", COMMANDS[gesture])   # <- Spot hook point
        fired = gesture

    label = f"{gesture} ({conf:.2f})"
    if gesture in COMMANDS and stable_count >= HOLD_FRAMES:
        label += " -> " + COMMANDS[gesture]
    color = (0, 255, 0) if gesture in COMMANDS else (0, 200, 255)
    cv2.putText(frame, label, (10, 40),
        cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 2)

    cv2.imshow("Gesture Control (trained model)", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()