import cv2, numpy as np
from calibration import object_calibration
from hand_detection import detect_hands, check_hand
from helper import compute_distance
from source.UI.hud import find_hud_placement
import math

from config import PIXELS_PER_INCH, CIRCLE_TOUCH_THRESHOLD
from config import FRAME_INTERVAL, TARGET_FPS
from config import DEBUG
from setup import InitCameras
#from hud import draw_hud_box, draw_pdf_page
import time

# ----- Global State -----
measuring = False             # measurement in progress
start_pt = None               # measurement start point
calibrating = False           # pinch-based calibration flag
object_calibrating = False    # object calibration flag
fingertip_idx_global = None   # last detected fingertip position

hud_pos = None
hud_rot = None
register_hud = False

# ----- Per-camera Processing -----
def process_frame(frame, camera_id: int = 0):
    global measuring, start_pt, calibrating
    global object_calibrating
    global fingertip_idx_global
    
    global register_hud, hud_pos, hud_rot

    frame_vis = cv2.flip(frame, 1)

    # Hand detection
    results = detect_hands(frame_vis)

    fingertip_idx = None
    if results.multi_hand_landmarks:
        hand = results.multi_hand_landmarks[0]
        fingertip_idx, measuring, start_pt = check_hand(hand, frame_vis, object_calibrating)

    fingertip_idx_global = fingertip_idx
 
    # object calibration
    if object_calibrating and fingertip_idx is not None:
        object_calibration(frame_vis, fingertip_idx, CIRCLE_TOUCH_THRESHOLD)
        object_calibrating = False
    
    # place hud
    res = None
    if hud_pos is None:
        res = find_hud_placement(frame_vis)
    else:
        res = hud_pos, hud_rot

    # create proj output
    projection_out = np.zeros_like(frame)
    
    # measuring
    if measuring and start_pt and fingertip_idx_global:
        cv2.line(projection_out, start_pt, fingertip_idx_global, (255,0,0),2)
        px = compute_distance(start_pt, fingertip_idx_global)
        inch = px/PIXELS_PER_INCH; cm = inch*2.54
        mid = ((start_pt[0]+fingertip_idx_global[0])//2,(start_pt[1]+fingertip_idx_global[1])//2)
        cv2.putText(projection_out,f"{inch:.2f}in/{cm:.1f}cm",(mid[0]+10,mid[1]-10), cv2.FONT_HERSHEY_SIMPLEX,0.7,(255,0,255),2)

    # hud
    if res is not None or hud_pos:
        if hud_pos:
            arrow_tip = hud_pos
            dir_vec = hud_rot
        else:
            arrow_tip, dir_vec = res

        dx, dy = dir_vec
        arrow_angle = math.atan2(dy, dx)   # result in radians
        #quad = draw_hud_box(projection_out, arrow_tip, arrow_angle, size=(400,400))
        #draw_pdf_page(projection_out, page_index=0, dst_quad=quad)

        if register_hud:
            hud_pos = arrow_tip
            hud_rot = dir_vec
            register_hud = False

    
    mask = cv2.cvtColor(projection_out, cv2.COLOR_BGR2GRAY) > 0
    frame_vis[mask] = projection_out[mask]

    return frame_vis, projection_out

# ----- Main ----- -------------------------------------------------------------------------------------
def main():
    all_captures = InitCameras()
    
    print(f"Running at up to {TARGET_FPS} FPS (interval={FRAME_INTERVAL:.3f}s)")
    print("Press 'o' for circle calib, 'q' to quit.")

    last_time = time.time()
    while True:
        processed_frames = []

        for camera_id, capture in enumerate(all_captures):
            ok, frame = capture.read()
            if not ok or frame is None:
                continue

            projection, debug = process_frame(frame, camera_id)
            processed_frames.append((camera_id, projection, debug))

        if not processed_frames:
            break

        for camera_id, projection, debug in processed_frames:
            if DEBUG:
                cv2.imshow(f'Debug Output (cam {camera_id})', debug)
            cv2.imshow(f'Projector Output (cam {camera_id})', projection)

        key = cv2.waitKey(1) & 0xFF

        if key == ord('q'):
            break
        elif key == ord('o'):
            global object_calibrating
            object_calibrating = True
            print("Entered circle calibration mode.")
        elif key == ord('j'):
            global register_hud, hud_pos
            register_hud = True
            hud_pos = None

        # ——— frame‐rate limiting ———
        now     = time.time()
        elapsed = now - last_time
        to_wait = FRAME_INTERVAL - elapsed
        if to_wait > 0:
            time.sleep(to_wait)
        last_time = time.time()

    for capture in all_captures:
        capture.release()

    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()
