import cv2
import math
import mediapipe as mp

class HandTracker:
    """
    Module 2: The Spatial Hand Engine (Enterprise Edition)
    """
    def __init__(self, max_hands=2, detection_confidence=0.7, tracking_confidence=0.7):
        print("[Aelion Vision] Booting Spatial Hand Engine...")
        self.mp_hands = mp.solutions.hands
        self.mp_draw = mp.solutions.drawing_utils
        
        self.hands = self.mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=max_hands,
            min_detection_confidence=detection_confidence,
            min_tracking_confidence=tracking_confidence
        )
        self.lm_list = [] 
        self.tip_ids = [4, 8, 12, 16, 20]

    def find_hands(self, frame, draw=True):
        img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        results = self.hands.process(img_rgb)
        
        self.lm_list = []
        
        if results.multi_hand_landmarks:
            for hand_lms in results.multi_hand_landmarks:
                if draw:
                    self.mp_draw.draw_landmarks(frame, hand_lms, self.mp_hands.HAND_CONNECTIONS)
                
                my_hand = results.multi_hand_landmarks[0]
                for id, lm in enumerate(my_hand.landmark):
                    h, w, c = frame.shape
                    cx, cy = int(lm.x * w), int(lm.y * h)
                    self.lm_list.append([id, cx, cy])
                    
        return frame

    def fingers_up(self):
        if len(self.lm_list) == 0:
            return []

        fingers = []
        if self.lm_list[self.tip_ids[0]][1] > self.lm_list[self.tip_ids[0] - 1][1]:
            fingers.append(1)
        else:
            fingers.append(0)

        for id in range(1, 5):
            if self.lm_list[self.tip_ids[id]][2] < self.lm_list[self.tip_ids[id] - 2][2]:
                fingers.append(1)
            else:
                fingers.append(0)

        return fingers

    def count_fingers(self):
        fingers = self.fingers_up()
        if not fingers:
            return 0
        return sum(fingers)

    def get_distance(self, p1_id, p2_id, frame=None, draw=True):
        if len(self.lm_list) == 0:
            return 0
            
        x1, y1 = self.lm_list[p1_id][1], self.lm_list[p1_id][2]
        x2, y2 = self.lm_list[p2_id][1], self.lm_list[p2_id][2]
        cx, cy = (x1 + x2) // 2, (y1 + y2) // 2

        if draw and frame is not None:
            cv2.circle(frame, (x1, y1), 10, (255, 0, 255), cv2.FILLED)
            cv2.circle(frame, (x2, y2), 10, (255, 0, 255), cv2.FILLED)
            cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 255), 3)
            cv2.circle(frame, (cx, cy), 10, (0, 255, 0), cv2.FILLED)

        length = math.hypot(x2 - x1, y2 - y1)
        return int(length)