"""
Close call / event detector for referee system.
Watches the trajectory model and triggers VAR when ball lands near a line.
"""

import time
from typing import Optional, Tuple, List, Dict
from .trajectory import TrajectoryModel

# Court line definitions in meters (X=along court, Y=across court)
# Full court: 13.4 x 6.1
COURT_LENGTH = 13.4
COURT_WIDTH = 6.1
HALF = COURT_LENGTH / 2  # 6.7 (net / center line)
NVZ = 2.13  # non-volley zone (kitchen) depth from net

COURT_LINES = {
    'baseline_left': {'type': 'horizontal', 'x': 0, 'y_start': 0, 'y_end': COURT_WIDTH},
    'baseline_right': {'type': 'horizontal', 'x': COURT_LENGTH, 'y_start': 0, 'y_end': COURT_WIDTH},
    'sideline_near': {'type': 'vertical', 'y': 0, 'x_start': 0, 'x_end': COURT_LENGTH},
    'sideline_far': {'type': 'vertical', 'y': COURT_WIDTH, 'x_start': 0, 'x_end': COURT_LENGTH},
    'centerline': {'type': 'horizontal', 'x': HALF, 'y_start': 0, 'y_end': COURT_WIDTH},
    'kitchen_left': {'type': 'horizontal', 'x': HALF - NVZ, 'y_start': 0, 'y_end': COURT_WIDTH},
    'kitchen_right': {'type': 'horizontal', 'x': HALF + NVZ, 'y_start': 0, 'y_end': COURT_WIDTH},
    'center_service_left': {'type': 'vertical', 'y': COURT_WIDTH / 2,
                            'x_start': 0, 'x_end': HALF - NVZ},
    'center_service_right': {'type': 'vertical', 'y': COURT_WIDTH / 2,
                             'x_start': HALF + NVZ, 'x_end': COURT_LENGTH},
}


class EventDetector:
    """Detects close calls by monitoring ball trajectory near court lines."""

    def __init__(self, trigger_distance_m=0.3, cooldown_seconds=5.0):
        self.trigger_distance = trigger_distance_m
        self.cooldown = cooldown_seconds
        self.last_trigger_time = 0.0
        self.events: List[Dict] = []

    def check(self, trajectory: TrajectoryModel) -> Optional[Dict]:
        """Check if current trajectory warrants a VAR trigger.

        Conditions:
        1. Ball is descending (vz < 0) or near ground (z < 0.3m)
        2. Predicted landing point is within trigger_distance of a line
        3. Cooldown has passed since last trigger
        """
        now = time.time()
        if now - self.last_trigger_time < self.cooldown:
            return None

        if not trajectory.points or trajectory.velocity is None:
            return None

        last = trajectory.points[-1]
        vz = trajectory.velocity[2]

        # Ball must be descending or near ground
        if vz > 0 and last.z > 0.5:
            return None

        # Get predicted landing
        landing = trajectory.predict_landing()
        if landing is None:
            return None

        land_x, land_y, time_to_land = landing

        # Check distance to each line
        closest_line = None
        closest_dist = float('inf')

        for name, line in COURT_LINES.items():
            dist = self._distance_to_line(land_x, land_y, line)
            if dist < closest_dist:
                closest_dist = dist
                closest_line = name

        if closest_dist <= self.trigger_distance:
            self.last_trigger_time = now
            event = {
                'type': 'close_call',
                'timestamp': now,
                'line': closest_line,
                'distance_m': closest_dist,
                'landing_x': land_x,
                'landing_y': land_y,
                'time_to_land': time_to_land,
                'ball_z': last.z,
                'ball_speed': trajectory.get_speed(),
            }
            self.events.append(event)
            return event

        return None

    def _distance_to_line(self, x: float, y: float, line: Dict) -> float:
        if line['type'] == 'horizontal':
            lx = line['x']
            y_start, y_end = line['y_start'], line['y_end']
            if y_start <= y <= y_end:
                return abs(x - lx)
            return float('inf')
        else:  # vertical
            ly = line['y']
            x_start, x_end = line['x_start'], line['x_end']
            if x_start <= x <= x_end:
                return abs(y - ly)
            return float('inf')

    def is_in_bounds(self, x: float, y: float) -> bool:
        return 0 <= x <= COURT_LENGTH and 0 <= y <= COURT_WIDTH
