"""Orchestrator that runs all NMS detectors and returns combined events."""

from ..constants import ALL_DETECTORS
from ..processing.utils import build_idx_to_frame
from .eyes import detect_eye_gaze_events, detect_eye_squint, detect_eyebrow_events
from .head import detect_head_oscillations, detect_head_tilts, detect_single_head_movements
from .mouth import detect_lip_activity


def detect_all_nms(
    pose,
    jaw_pose,
    expression,
    successful_frames,
    valid,
    segments,
    *,
    detectors=None,
    nod_amplitude=0.010,
    shake_amplitude=0.025,
    tilt_threshold=0.06,
    mouth_threshold=0.06,
    eyebrow_threshold=1.0,
    leye_pose=None,
    reye_pose=None,
    gaze_threshold=1.5,
    eyelid=None,
    blink_events=None,
    squint_threshold=0.03,
    lip_threshold=0.15,
    verbose=False,
):
    """Run all non-manual signal detectors and return combined event list."""
    if detectors is None:
        detectors = ALL_DETECTORS
    else:
        detectors = set(detectors) & ALL_DETECTORS

    idx_to_frame = build_idx_to_frame(successful_frames)

    events = []

    if "nod" in detectors and pose is not None:
        nods = detect_head_oscillations(
            pose[:, 0],
            successful_frames,
            valid,
            segments,
            tier="HEAD-NOD",
            min_amplitude=nod_amplitude,
            idx_to_frame=idx_to_frame,
        )
        single_nods = detect_single_head_movements(
            pose[:, 0],
            successful_frames,
            valid,
            segments,
            tier="HEAD-NOD",
            min_amplitude=nod_amplitude,
            existing_events=nods,
            idx_to_frame=idx_to_frame,
        )
        events.extend(nods)
        events.extend(single_nods)
        if verbose:
            print(
                f"  HEAD-NOD: {len(nods)} oscillatory + {len(single_nods)} single = {len(nods) + len(single_nods)} total"
            )

    if "shake" in detectors and pose is not None:
        shakes = detect_head_oscillations(
            pose[:, 1],
            successful_frames,
            valid,
            segments,
            tier="HEAD-SHAKE",
            min_amplitude=shake_amplitude,
            idx_to_frame=idx_to_frame,
        )
        single_shakes = detect_single_head_movements(
            pose[:, 1],
            successful_frames,
            valid,
            segments,
            tier="HEAD-SHAKE",
            min_amplitude=shake_amplitude,
            existing_events=shakes,
            idx_to_frame=idx_to_frame,
        )
        events.extend(shakes)
        events.extend(single_shakes)
        if verbose:
            print(
                f"  HEAD-SHAKE: {len(shakes)} oscillatory + {len(single_shakes)} single = {len(shakes) + len(single_shakes)} total"
            )

    if "tilt" in detectors and pose is not None:
        tilts = detect_head_tilts(
            pose[:, 2],
            successful_frames,
            valid,
            segments,
            threshold=tilt_threshold,
            idx_to_frame=idx_to_frame,
        )
        events.extend(tilts)
        if verbose:
            print(f"  HEAD-TILT: {len(tilts)} events")

    if "mouth" in detectors and expression is not None:
        lip_events = detect_lip_activity(
            expression,
            successful_frames,
            valid,
            segments,
            threshold=lip_threshold,
            idx_to_frame=idx_to_frame,
        )
        for e in lip_events:
            e.tier = "MOUTH-MOVEMENT"
            e.label = "mouth movement"
            events.append(e)
        if verbose:
            print(f"  MOUTH-MOVEMENT: {len(lip_events)} events")

    if "eyebrow" in detectors and expression is not None:
        brows = detect_eyebrow_events(
            expression,
            successful_frames,
            valid,
            segments,
            threshold_std=eyebrow_threshold,
            idx_to_frame=idx_to_frame,
            pose=pose,
        )
        events.extend(brows)
        if verbose:
            raises = [e for e in brows if e.tier == "EYEBROW-RAISE"]
            furrows = [e for e in brows if e.tier == "EYEBROW-FURROW"]
            print(f"  EYEBROW-RAISE: {len(raises)} events")
            print(f"  EYEBROW-FURROW: {len(furrows)} events")

    if "gaze" in detectors and leye_pose is not None and reye_pose is not None:
        gaze_events = detect_eye_gaze_events(
            leye_pose,
            reye_pose,
            successful_frames,
            valid,
            segments,
            threshold_factor=gaze_threshold,
            idx_to_frame=idx_to_frame,
        )
        events.extend(gaze_events)
        if verbose:
            print(f"  EYE-GAZE: {len(gaze_events)} events")

    if "squint" in detectors and eyelid is not None:
        squints = detect_eye_squint(
            eyelid,
            successful_frames,
            valid,
            segments,
            threshold=squint_threshold,
            blink_events=blink_events,
            idx_to_frame=idx_to_frame,
        )
        events.extend(squints)
        if verbose:
            print(f"  EYE-SQUINT: {len(squints)} events")

    if "lips" in detectors and "mouth" not in detectors and expression is not None:
        lip_events = detect_lip_activity(
            expression,
            successful_frames,
            valid,
            segments,
            threshold=lip_threshold,
            idx_to_frame=idx_to_frame,
        )
        for e in lip_events:
            e.tier = "MOUTH-MOVEMENT"
            e.label = "mouth movement"
            events.append(e)
        if verbose:
            print(f"  MOUTH-MOVEMENT (lips only): {len(lip_events)} events")

    events.sort(key=lambda e: e.start_frame)
    return events
