#!/usr/bin/env python3
import sys
import os
import time
import argparse
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.mouse_button import MouseButton

class CursorController:
    def __init__(self, debug_port: int, verbose: bool = False):
        """Initialize connection to Chrome instance"""
        self.verbose = verbose
        options = webdriver.ChromeOptions()
        options.add_experimental_option("debuggerAddress", f"127.0.0.1:{debug_port}")
        self.driver = webdriver.Chrome(options=options)
        
        # Load JavaScript files
        js_dir = os.path.join(os.path.dirname(__file__), "..", "js")
        self.js_code = ""
        for filename in ["viewport.js", "mouse.js"]:
            with open(os.path.join(js_dir, filename)) as f:
                self.js_code += f.read() + "\n"

    def log(self, msg: str):
        """Log message if verbose mode is enabled"""
        if self.verbose:
            print(f"DEBUG: {msg}", file=sys.stderr)

    def get_viewport_info(self):
        """Get viewport dimensions and scroll position"""
        return self.driver.execute_script(self.js_code + "; return getViewportInfo();")

    def get_mouse_position(self):
        """Get current mouse coordinates"""
        return self.driver.execute_script(self.js_code + "; return getMousePosition();")

    def scroll_to_target(self, x: int, y: int):
        """Scroll viewport to make target coordinates visible"""
        viewport = self.get_viewport_info()
        self.driver.execute_script(
            "window.scrollTo(arguments[0], arguments[1]);",
            max(0, x - viewport['width'] // 2),
            max(0, y - viewport['height'] // 2)
        )
        time.sleep(0.5)  # Wait for scroll to complete

    def get_element_at_position(self, x: int, y: int):
        """Get the element at specified coordinates"""
        return self.driver.execute_script(
            self.js_code + "; return document.elementFromPoint(arguments[0], arguments[1]);",
            x, y
        )

    def move_cursor(self, x: int, y: int, perform_click: bool = False,
                   double_click: bool = False, right_click: bool = False,
                   element_id: str = None) -> bool:
        """Move cursor to specified coordinates and optionally perform click actions"""
        try:
            self.log(f"Moving cursor to ({x}, {y})")
            
            if element_id:
                # Try to find element by ID first
                try:
                    element = self.driver.find_element(By.ID, element_id)
                    self.log(f"Found element by ID: {element_id}")
                except:
                    self.log(f"Failed to find element by ID: {element_id}")
                    return False
            else:
                # Scroll to make target visible
                self.scroll_to_target(x, y)
                
                # Get element at position
                element = self.get_element_at_position(x, y)
                if not element:
                    self.log(f"No element found at coordinates ({x}, {y})")
                    return False

            # Create action chain
            actions = ActionChains(self.driver)
            
            if element_id:
                actions.move_to_element(element)
            else:
                actions.move_by_offset(x, y)

            if perform_click:
                actions.click()
            elif double_click:
                actions.double_click()
            elif right_click:
                actions.context_click()

            # Execute the action chain
            actions.perform()
            return True

        except Exception as e:
            self.log(f"Error moving cursor: {str(e)}")
            return False

def main():
    parser = argparse.ArgumentParser(description='Control mouse cursor in Chrome')
    parser.add_argument('debug_port', type=int, help='Chrome debug port')
    parser.add_argument('-x', type=int, help='Target X coordinate')
    parser.add_argument('-y', type=int, help='Target Y coordinate')
    parser.add_argument('--click', action='store_true', help='Perform click')
    parser.add_argument('--double', action='store_true', help='Perform double click')
    parser.add_argument('--right', action='store_true', help='Perform right click')
    parser.add_argument('--id', help='Element ID to target')
    parser.add_argument('-v', '--verbose', action='store_true', help='Enable debug output')
    
    args = parser.parse_args()

    if args.double and args.right:
        print("Cannot specify both --double and --right", file=sys.stderr)
        sys.exit(1)
        
    if not args.id and (args.x is None or args.y is None):
        print("Must specify either element ID or both x and y coordinates", file=sys.stderr) 
        sys.exit(1)
        
    try:
        controller = CursorController(args.debug_port, args.verbose)
        success = controller.move_cursor(
            x=args.x if args.x is not None else 0,
            y=args.y if args.y is not None else 0,
            perform_click=args.click,
            double_click=args.double,
            right_click=args.right,
            element_id=args.id
        )
        sys.exit(0 if success else 1)
        
    except Exception as e:
        if args.verbose:
            print(f"Fatal error: {str(e)}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()