"""
Behavioral Jitter Engine — Genesis Superior Browser
===================================================
Simulates human-parity mouse movements using non-linear
Bezier curves, variable deceleration, and 'idle thoughts'
(scrolling without clicking, hovering on non-interactive elements)
to defeat advanced bot managers (Akamai, DataDome).
"""

import math
import random
import time
import logging
from typing import List, Tuple

try:
    import pyautogui
except ImportError:
    pyautogui = None

logger = logging.getLogger("genesis_v2.core.browser.jitter_engine")

class JitterEngine:
    def __init__(self):
        self.simulation_mode = pyautogui is None
        if not self.simulation_mode:
            pyautogui.MINIMUM_DURATION = 0.1
            pyautogui.MINIMUM_SLEEP = 0.05
            
    def _generate_bezier_curve(self, start: Tuple[int, int], end: Tuple[int, int], num_points: int = 20) -> List[Tuple[int, int]]:
        """Generates a cubic Bezier curve for natural mouse movement."""
        x0, y0 = start
        x3, y3 = end
        
        # Calculate random control points to simulate human 'wobble'
        distance = math.hypot(x3 - x0, y3 - y0)
        deviation = min(distance * 0.3, 150) # Max pixel deviation
        
        x1 = x0 + (x3 - x0) * 0.3 + random.uniform(-deviation, deviation)
        y1 = y0 + (y3 - y0) * 0.3 + random.uniform(-deviation, deviation)
        
        x2 = x0 + (x3 - x0) * 0.7 + random.uniform(-deviation, deviation)
        y2 = y0 + (y3 - y0) * 0.7 + random.uniform(-deviation, deviation)
        
        points = []
        for i in range(num_points + 1):
            t = i / num_points
            
            # Cubic Bezier formula
            x = (1-t)**3 * x0 + 3*(1-t)**2 * t * x1 + 3*(1-t) * t**2 * x2 + t**3 * x3
            y = (1-t)**3 * y0 + 3*(1-t)**2 * t * y1 + 3*(1-t) * t**2 * y2 + t**3 * y3
            
            points.append((int(x), int(y)))
            
        return points

    def human_move_to(self, x: int, y: int):
        """Moves the mouse to the specified coordinates with human-like jitter."""
        if self.simulation_mode:
            logger.info(f"Simulation: Human move to ({x}, {y})")
            return
            
        current_x, current_y = pyautogui.position()
        logger.info(f"Jitter Engine: Interpolating from ({current_x},{current_y}) to ({x},{y})")
        
        points = self._generate_bezier_curve((current_x, current_y), (x, y))
        
        total_time = random.uniform(0.3, 0.8) # Total time to complete move
        time_per_segment = total_time / len(points)
        
        for px, py in points:
            # Add micro-jitters to individual steps to avoid perfect mathematical curves
            micro_x = px + random.randint(-1, 1)
            micro_y = py + random.randint(-1, 1)
            pyautogui.moveTo(micro_x, micro_y, _pause=False)
            
            # Fitts' Law simulation: slow down as we approach the target
            distance_to_target = math.hypot(x - px, y - py)
            if distance_to_target < 50:
                time.sleep(time_per_segment * 1.5)
            else:
                time.sleep(time_per_segment)
                
    def perform_idle_thought(self):
        """Simulates a human 'thinking' or reading the screen (scrolling, hovering)."""
        if self.simulation_mode:
            logger.info("Simulation: Performing idle thought")
            return
            
        logger.info("Jitter Engine: Performing idle thought")
        actions = ["micro_scroll", "hover_text", "do_nothing"]
        action = random.choice(actions)
        
        if action == "micro_scroll":
            scroll_amount = random.randint(-15, 15)
            # Avoid perfectly smooth scrolls
            for _ in range(abs(scroll_amount)):
                pyautogui.scroll(1 if scroll_amount > 0 else -1)
                time.sleep(random.uniform(0.01, 0.05))
        elif action == "hover_text":
            # Move mouse slightly in x direction, as if tracing text
            current_x, current_y = pyautogui.position()
            trace_distance = random.randint(20, 100)
            self.human_move_to(current_x + trace_distance, current_y + random.randint(-5, 5))
        else:
            time.sleep(random.uniform(0.5, 2.0))
