"""
Decorator for making functions remotely callable
"""

import functools
import inspect
from typing import Callable
from .server import start_server, register_function, is_server_running
from .client import create_remote_function


def shared(func: Callable) -> Callable:
    """
    Decorator that makes a function callable across processes.
    
    When called from the same process where it's defined, it executes locally.
    When imported from another process, it makes HTTP calls to the server.
    
    Usage:
        @shared
        def my_function(x, y):
            return x + y
    """
    
    # Get the module where the function is defined
    func_module = inspect.getmodule(func)
    func_name = func.__name__
    
    # Determine the qualified name, handling the case where the module is run as __main__
    module_name = ""
    if func_module:
        if func_module.__name__ == '__main__':
            # If run as a script, derive the module name from the file path
            # This is crucial for the client to find it.
            import os
            base_path = os.path.abspath(os.getcwd())
            file_path = os.path.abspath(func_module.__file__)
            if file_path.startswith(base_path):
                # Remove base path and .py extension, replace slashes with dots
                module_name = os.path.splitext(file_path[len(base_path)+1:])[0].replace(os.sep, '.')
        else:
            module_name = func_module.__name__
            
    qualified_name = f"{module_name}.{func_name}" if module_name else func_name
    
    # Register the function
    register_function(qualified_name, func)
    
    # Start server if not running, but only if the function's module is the main entry point
    if func_module and func_module.__name__ == '__main__' and not is_server_running():
        start_server()
    
    # Create a wrapper that decides whether to call locally or remotely
    _is_local = None

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        nonlocal _is_local
        
        # Check if we're in the same process by seeing if the function
        # object is the same (identity check)
        if _is_local is None:
            calling_frame = inspect.currentframe()
            if calling_frame:
                calling_module = inspect.getmodule(calling_frame.f_back)
                
                # If called from the same module where it's defined, execute locally
                _is_local = (calling_module == func_module)
            else:
                _is_local = False
        
        if _is_local:
            return func(*args, **kwargs)
        
        # Otherwise, make a remote call
        remote_func = create_remote_function(qualified_name)
        return remote_func(*args, **kwargs)
    
    # Store original function for potential direct access
    wrapper.__wrapped__ = func
    wrapper.__remote_name__ = qualified_name
    
    return wrapper
