"""
CSSL Bridge - Python API for CSSL Language
Provides CsslLang class for executing CSSL code from Python.

v3.8.0 API:
    cssl.run(code, *args)          - Execute CSSL code
    cssl.script("cssl", code)      - Create typed script
    cssl.makemodule(script, pl)    - Bundle main script + payload
    cssl.load(path, name)          - Load .cssl/.cssl-pl file
    cssl.execute(name)             - Execute loaded script
    cssl.include(path, name)       - Register for payload(name)
"""

import os
import pickle
import random
import threading
import warnings
from pathlib import Path
from typing import Any, List, Optional, Callable, Dict, Union, Tuple


def _get_share_directory() -> Path:
    """Get the directory for shared objects."""
    # Use APPDATA on Windows, ~/.config on Unix
    if os.name == 'nt':
        base = Path(os.environ.get('APPDATA', Path.home() / 'AppData' / 'Roaming'))
    else:
        base = Path(os.environ.get('XDG_CONFIG_HOME', Path.home() / '.config'))

    share_dir = base / 'IncludeCPP' / 'shared_objects'
    share_dir.mkdir(parents=True, exist_ok=True)
    return share_dir


# Global live object registry - holds actual object references for live sharing
_live_objects: Dict[str, Any] = {}


class SharedObjectProxy:
    """
    Live proxy for accessing a shared Python object from CSSL.
    Changes made through this proxy are reflected in the original object.
    """

    def __init__(self, name: str, obj: Any = None):
        object.__setattr__(self, '_name', name)
        object.__setattr__(self, '_direct_object', obj)

    def _get_object(self):
        """Get the live object reference."""
        # First check direct object (same-instance sharing)
        direct = object.__getattribute__(self, '_direct_object')
        if direct is not None:
            return direct

        # Fall back to global registry
        name = object.__getattribute__(self, '_name')
        if name in _live_objects:
            return _live_objects[name]

        return None

    def __getattr__(self, name: str):
        """Access attributes/methods on the shared object."""
        obj = self._get_object()
        if obj is None:
            obj_name = object.__getattribute__(self, '_name')
            raise AttributeError(f"Shared object '${obj_name}' not available")

        return getattr(obj, name)

    def __setattr__(self, name: str, value: Any):
        """Set attributes on the shared object (live update)."""
        if name.startswith('_'):
            object.__setattr__(self, name, value)
            return

        obj = self._get_object()
        if obj is None:
            obj_name = object.__getattribute__(self, '_name')
            raise AttributeError(f"Shared object '${obj_name}' not available")

        setattr(obj, name, value)

    def __repr__(self):
        obj = self._get_object()
        name = object.__getattribute__(self, '_name')
        return f"<SharedObject ${name} type={type(obj).__name__ if obj else 'None'}>"

    def __call__(self, *args, **kwargs):
        """Allow calling the object if it's callable."""
        obj = self._get_object()
        if obj is None:
            name = object.__getattribute__(self, '_name')
            raise TypeError(f"Shared object '${name}' not available")
        if callable(obj):
            return obj(*args, **kwargs)
        name = object.__getattribute__(self, '_name')
        raise TypeError(f"Shared object '${name}' is not callable")

    def __getitem__(self, key):
        """Allow indexing on the shared object."""
        obj = self._get_object()
        if obj is None:
            name = object.__getattribute__(self, '_name')
            raise KeyError(f"Shared object '${name}' not available")
        return obj[key]

    def __setitem__(self, key, value):
        """Allow setting items on the shared object (live update)."""
        obj = self._get_object()
        if obj is None:
            name = object.__getattribute__(self, '_name')
            raise KeyError(f"Shared object '${name}' not available")
        obj[key] = value

    def __iter__(self):
        """Allow iterating over the shared object."""
        obj = self._get_object()
        if obj is None:
            name = object.__getattribute__(self, '_name')
            raise TypeError(f"Shared object '${name}' not available")
        return iter(obj)

    def __len__(self):
        """Get length of the shared object."""
        obj = self._get_object()
        if obj is None:
            return 0
        return len(obj)


class CSSLModule:
    """
    A callable CSSL module that executes code with arguments.

    Created via CSSL.module() - the code is executed each time the module is called,
    with arguments accessible via parameter.get(index).
    """

    def __init__(self, cssl_instance: 'CsslLang', code: str):
        self._cssl = cssl_instance
        self._code = code

    def __call__(self, *args) -> Any:
        """Execute the module code with the given arguments."""
        return self._cssl.exec(self._code, *args)

    def __repr__(self) -> str:
        return f"<CSSLModule code_len={len(self._code)}>"


class CSSLScript:
    """
    A typed CSSL script object.

    Created via cssl.script("cssl", code) or cssl.script("cssl-pl", code).
    Can be executed directly or bundled into a module.

    Usage:
        main = cssl.script("cssl", '''
            printl("Main script");
            myFunc();
        ''')

        payload = cssl.script("cssl-pl", '''
            void myFunc() {
                printl("From payload!");
            }
        ''')

        # Execute directly
        main.run()

        # Or bundle into module
        mod = cssl.makemodule(main, payload, "mymod")
    """

    def __init__(self, cssl_instance: 'CsslLang', script_type: str, code: str, params: Tuple = ()):
        """
        Initialize a CSSL script.

        Args:
            cssl_instance: The parent CsslLang instance
            script_type: "cssl" for main script, "cssl-pl" for payload
            code: The CSSL code
            params: Optional parameters accessible via parameter.get(index)
        """
        if script_type not in ('cssl', 'cssl-pl'):
            raise ValueError(f"Invalid script type '{script_type}'. Must be 'cssl' or 'cssl-pl'")

        self._cssl = cssl_instance
        self._type = script_type
        self._code = code
        self._params = params
        self._name: Optional[str] = None

    @property
    def type(self) -> str:
        """Get script type ('cssl' or 'cssl-pl')."""
        return self._type

    @property
    def code(self) -> str:
        """Get the script code."""
        return self._code

    @property
    def is_payload(self) -> bool:
        """Check if this is a payload script."""
        return self._type == 'cssl-pl'

    def run(self, *args) -> Any:
        """Execute this script with optional arguments."""
        all_args = self._params + args
        return self._cssl.run(self._code, *all_args)

    def __call__(self, *args) -> Any:
        """Allow calling the script directly."""
        return self.run(*args)

    def __repr__(self) -> str:
        return f"<CSSLScript type='{self._type}' code_len={len(self._code)}>"


class CSSLFunctionModule:
    """
    A CSSL module with accessible functions as methods.

    Created via CSSL.makemodule() - functions defined in the CSSL code
    become callable attributes on this module.
    """

    def __init__(self, cssl_instance: 'CsslLang', code: str, payload_code: str = None, name: str = None):
        self._cssl = cssl_instance
        self._code = code
        self._payload_code = payload_code
        self._name = name
        self._runtime = None
        self._functions: Dict[str, Any] = {}
        self._initialized = False

    def _ensure_initialized(self):
        """Initialize the module by parsing and registering functions."""
        if self._initialized:
            return

        from .cssl import CSSLRuntime, parse_cssl_program, ASTNode

        # Create a dedicated runtime for this module
        self._runtime = CSSLRuntime()

        # If we have a payload, load it first (defines functions/globals for main)
        if self._payload_code:
            payload_ast = parse_cssl_program(self._payload_code)
            for child in payload_ast.children:
                if child.type == 'function':
                    func_info = child.value
                    func_name = func_info.get('name')
                    self._functions[func_name] = child
                    self._runtime.scope.set(func_name, child)
                else:
                    try:
                        self._runtime._execute_node(child)
                    except Exception:
                        pass

        # Parse the main code
        ast = parse_cssl_program(self._code)

        # Execute to register all function definitions
        for child in ast.children:
            if child.type == 'function':
                func_info = child.value
                func_name = func_info.get('name')
                self._functions[func_name] = child
                self._runtime.scope.set(func_name, child)
            else:
                # Execute other statements (like struct definitions)
                try:
                    self._runtime._execute_node(child)
                except Exception:
                    pass

        # If module has a name, register for payload() access
        if self._name:
            cssl_instance = self._cssl
            runtime = cssl_instance._get_runtime()
            if not hasattr(runtime, '_inline_payloads'):
                runtime._inline_payloads = {}
            # Store combined code for payload() access
            combined = (self._payload_code or '') + '\n' + self._code
            runtime._inline_payloads[self._name] = combined

        self._initialized = True

    def __getattr__(self, name: str) -> Callable:
        """Get a function from the module."""
        # Avoid recursion for internal attributes
        if name.startswith('_'):
            raise AttributeError(f"'{type(self).__name__}' has no attribute '{name}'")

        self._ensure_initialized()

        if name in self._functions:
            func_node = self._functions[name]

            def wrapper(*args):
                from .cssl import Parameter
                # Set up parameter object for this call
                self._runtime.global_scope.set('parameter', Parameter(list(args)))
                self._runtime.global_scope.set('args', list(args))
                self._runtime.global_scope.set('argc', len(args))
                return self._runtime._call_function(func_node, list(args))

            return wrapper

        raise AttributeError(f"CSSL module has no function '{name}'")

    def __dir__(self) -> List[str]:
        """List available functions."""
        self._ensure_initialized()
        return list(self._functions.keys())

    def __repr__(self) -> str:
        self._ensure_initialized()
        funcs = ', '.join(self._functions.keys())
        return f"<CSSLFunctionModule functions=[{funcs}]>"


class CsslLang:
    """
    CSSL Language interface for Python.

    v3.8.0 API:
        from includecpp import CSSL
        cssl = CSSL.CsslLang()

        # Execute CSSL code
        result = cssl.run("script.cssl", arg1, arg2)
        result = cssl.run('''printl("Hello");''')

        # Create typed scripts
        main = cssl.script("cssl", '''printl("Main");''')
        payload = cssl.script("cssl-pl", '''void helper() {}''')

        # Bundle into module
        mod = cssl.makemodule(main, payload, "mymod")

        # Load and execute files
        cssl.load("utils.cssl-pl", "utils")
        cssl.execute("utils")

        # Register for payload() access
        cssl.include("helpers.cssl-pl", "helpers")
    """

    def __init__(self, output_callback: Optional[Callable[[str, str], None]] = None):
        """
        Initialize CSSL runtime.

        Args:
            output_callback: Optional callback for output (text, level)
        """
        self._output_callback = output_callback
        self._runtime = None
        self._threads: List[threading.Thread] = []
        self._loaded_scripts: Dict[str, Dict[str, Any]] = {}

    def _get_runtime(self):
        """Lazy load CSSL runtime."""
        if self._runtime is None:
            from .cssl import CSSLRuntime
            self._runtime = CSSLRuntime(output_callback=self._output_callback)
        return self._runtime

    def _detect_type(self, path: str) -> str:
        """Detect script type from file extension."""
        path_obj = Path(path)
        if path_obj.suffix == '.cssl-pl':
            return 'cssl-pl'
        return 'cssl'

    def run(self, path_or_code: str, *args) -> Any:
        """
        Execute CSSL code or file.

        This is the primary method for running CSSL code in v3.8.0+.

        Args:
            path_or_code: Path to .cssl file or CSSL code string
            *args: Arguments to pass to the script (accessible via parameter.get())

        Returns:
            Execution result. If parameter.return() was called, returns
            the list of returned values (or single value if only one).

        Usage:
            cssl.run("script.cssl", "arg1", 42)
            cssl.run('''
                printl("Hello " + parameter.get(0));
            ''', "World")
        """
        runtime = self._get_runtime()

        # Check if it's a file path
        path = Path(path_or_code)
        if path.exists() and path.suffix in ('.cssl', '.cssl-mod', '.cssl-pl'):
            source = path.read_text(encoding='utf-8')
        else:
            source = path_or_code

        # Set arguments in runtime scope
        from .cssl import Parameter
        param = Parameter(list(args))
        runtime.global_scope.set('args', list(args))
        runtime.global_scope.set('argc', len(args))
        runtime.global_scope.set('parameter', param)

        # Execute as standalone program
        try:
            result = runtime.execute_program(source)

            # Check if parameter.return() was used (generator-like returns)
            if param.has_returns():
                returns = param.returns()
                # Return single value if only one, else return list
                return returns[0] if len(returns) == 1 else returns

            return result
        except Exception as e:
            # Format error message nicely
            error_msg = str(e)
            # Don't double-wrap error messages
            if error_msg.startswith("CSSL Error:"):
                raise RuntimeError(error_msg) from e
            raise RuntimeError(f"CSSL Error:\n{error_msg}") from e

    def exec(self, path_or_code: str, *args) -> Any:
        """
        Execute CSSL code or file.

        DEPRECATED: Use run() instead. This method is kept for backwards compatibility.

        Args:
            path_or_code: Path to .cssl file or CSSL code string
            *args: Arguments to pass to the script

        Returns:
            Execution result
        """
        warnings.warn(
            "exec() is deprecated, use run() instead",
            DeprecationWarning,
            stacklevel=2
        )
        return self.run(path_or_code, *args)

    def T_run(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
        """
        Execute CSSL code asynchronously in a thread.

        Args:
            path_or_code: Path to .cssl file or CSSL code string
            *args: Arguments to pass to the script
            callback: Optional callback when execution completes

        Returns:
            Thread object
        """
        def _run_async():
            try:
                result = self.run(path_or_code, *args)
                if callback:
                    callback(result)
            except Exception as e:
                if callback:
                    callback(e)

        thread = threading.Thread(target=_run_async, daemon=True)
        thread.start()
        self._threads.append(thread)
        return thread

    def T_exec(self, path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
        """
        Execute CSSL code asynchronously in a thread.

        DEPRECATED: Use T_run() instead.
        """
        warnings.warn(
            "T_exec() is deprecated, use T_run() instead",
            DeprecationWarning,
            stacklevel=2
        )
        return self.T_run(path_or_code, *args, callback=callback)

    def wait_all(self, timeout: Optional[float] = None):
        """Wait for all async executions to complete."""
        for thread in self._threads:
            thread.join(timeout=timeout)
        self._threads.clear()

    def get_output(self) -> List[str]:
        """Get output buffer from last execution."""
        runtime = self._get_runtime()
        return list(runtime.output_buffer)

    def clear_output(self):
        """Clear output buffer."""
        runtime = self._get_runtime()
        runtime.output_buffer.clear()

    def set_global(self, name: str, value: Any):
        """Set a global variable in CSSL runtime."""
        runtime = self._get_runtime()
        runtime.global_scope.set(name, value)

    def get_global(self, name: str) -> Any:
        """Get a global variable from CSSL runtime."""
        runtime = self._get_runtime()
        return runtime.global_scope.get(name)

    def module(self, code: str) -> 'CSSLModule':
        """
        Create a callable CSSL module from code.

        The module can be called with arguments that are passed to the CSSL code.

        Usage:
            module = CSSL.module('''
                printl(parameter.get(0));
            ''')
            module("Hello")  # Prints "Hello"

        Args:
            code: CSSL code string

        Returns:
            CSSLModule - a callable module
        """
        return CSSLModule(self, code)

    def script(self, script_type: str, code: str, *params) -> 'CSSLScript':
        """
        Create a typed CSSL script.

        Args:
            script_type: "cssl" for main script, "cssl-pl" for payload
            code: The CSSL code
            *params: Optional parameters accessible via parameter.get(index)

        Returns:
            CSSLScript object that can be executed or bundled

        Usage:
            main = cssl.script("cssl", '''
                printl("Main script running");
                helper();
            ''')

            payload = cssl.script("cssl-pl", '''
                void helper() {
                    printl("Helper called!");
                }
            ''')

            # Execute directly
            main.run()

            # Or bundle into module
            mod = cssl.makemodule(main, payload, "mymod")
        """
        return CSSLScript(self, script_type, code, params)

    def makemodule(
        self,
        main_script: Union[str, 'CSSLScript'],
        payload_script: Union[str, 'CSSLScript', None] = None,
        name: str = None
    ) -> 'CSSLFunctionModule':
        """
        Create a CSSL module with accessible functions.

        Functions defined in the code become methods on the returned module.
        Optionally registers the module for payload() access in other scripts.

        Args:
            main_script: Main CSSL code (string or CSSLScript)
            payload_script: Optional payload code (string or CSSLScript)
            name: Optional name to register for payload(name) access

        Returns:
            CSSLFunctionModule - module with callable function attributes

        Usage (v3.8.0 - with CSSLScript objects):
            main = cssl.script("cssl", '''
                printl("Main");
                helper();
            ''')
            payload = cssl.script("cssl-pl", '''
                void helper() { printl("Helper!"); }
            ''')
            mod = cssl.makemodule(main, payload, "mymod")
            mod.helper()  # Direct call

            # Also available in other scripts:
            cssl.run('''
                payload("mymod");
                helper();  // Works!
            ''')

        Usage (legacy - code string):
            module = cssl.makemodule('''
                string greet(string name) {
                    return "Hello, " + name + "!";
                }
            ''')
            module.greet("World")  # Returns "Hello, World!"
        """
        # Extract code from CSSLScript objects if provided
        if isinstance(main_script, CSSLScript):
            main_code = main_script.code
        else:
            main_code = main_script

        payload_code = None
        if payload_script is not None:
            if isinstance(payload_script, CSSLScript):
                payload_code = payload_script.code
            else:
                payload_code = payload_script

        return CSSLFunctionModule(self, main_code, payload_code, name)

    def load(self, path: str, name: str) -> None:
        """
        Load a .cssl or .cssl-pl file and register by name.

        The file becomes accessible for execute(name) or payload(name).

        Args:
            path: Path to the .cssl or .cssl-pl file
            name: Name to register the script under

        Usage:
            cssl.load("utils.cssl-pl", "utils")
            cssl.execute("utils")  # Run it

            # Or in CSSL code:
            cssl.run('''
                payload("utils");  // Loads the registered file
            ''')
        """
        path_obj = Path(path)
        if not path_obj.exists():
            raise FileNotFoundError(f"CSSL file not found: {path}")

        script_type = self._detect_type(path)
        code = path_obj.read_text(encoding='utf-8')

        self._loaded_scripts[name] = {
            'path': str(path_obj.absolute()),
            'type': script_type,
            'code': code
        }

        # Also register for payload() access
        runtime = self._get_runtime()
        if not hasattr(runtime, '_inline_payloads'):
            runtime._inline_payloads = {}
        runtime._inline_payloads[name] = code

    def execute(self, name: str, *args) -> Any:
        """
        Execute a previously loaded script by name.

        Args:
            name: Name of the loaded script
            *args: Arguments to pass to the script

        Returns:
            Execution result

        Usage:
            cssl.load("utils.cssl-pl", "utils")
            result = cssl.execute("utils", arg1, arg2)
        """
        if name not in self._loaded_scripts:
            raise KeyError(f"No script loaded with name '{name}'. Use load() first.")

        script_info = self._loaded_scripts[name]
        return self.run(script_info['code'], *args)

    def include(self, path: str, name: str) -> None:
        """
        Register a file to be accessible via payload(name) or include(name) in CSSL.

        Unlike load(), this doesn't store the script for execute() - it only
        makes it available for payload() calls within CSSL code.

        Args:
            path: Path to the .cssl or .cssl-pl file
            name: Name for payload() access

        Usage:
            cssl.include("helpers.cssl-pl", "helpers")
            cssl.run('''
                payload("helpers");
                // Functions from helpers are now available
            ''')
        """
        path_obj = Path(path)
        if not path_obj.exists():
            raise FileNotFoundError(f"CSSL file not found: {path}")

        code = path_obj.read_text(encoding='utf-8')

        runtime = self._get_runtime()
        if not hasattr(runtime, '_inline_payloads'):
            runtime._inline_payloads = {}
        runtime._inline_payloads[name] = code

    def code(self, name: str, code: str) -> None:
        """
        Register inline CSSL code as a payload that can be loaded via payload().

        This allows creating payloads from Python code without external files.

        Usage:
            from includecpp import CSSL
            cssl = CSSL.CsslLang()

            # Register a helper payload
            cssl.code("helpers", '''
                global version = "1.0.0";
                void log(string msg) {
                    printl("[LOG] " + msg);
                }
            ''')

            # Use it in CSSL code
            cssl.exec('''
                payload("helpers");  // Load the inline payload
                @log("Hello!");      // Call the helper function
                printl(@version);    // Access the global
            ''')

        Args:
            name: Name to register the payload under (used in payload("name"))
            code: CSSL code string
        """
        runtime = self._get_runtime()
        if not hasattr(runtime, '_inline_payloads'):
            runtime._inline_payloads = {}
        runtime._inline_payloads[name] = code

    def share(self, instance: Any, name: str = None) -> str:
        """
        Share a Python object instance with CSSL scripts (LIVE sharing).

        The object is stored as a LIVE reference - changes made in CSSL
        will be reflected in the original Python object immediately.
        Call share() again with the same name to update the shared object.

        Args:
            instance: The Python object to share (or name if using old API)
            name: The name to reference the object in CSSL ($name)

        Note: Arguments can be passed in either order:
            cssl.share(my_object, "name")  # Preferred
            cssl.share("name", my_object)  # Also works

        Usage in Python:
            from includecpp import CSSL
            cssl = CSSL.CsslLang()

            # Share a Python object
            class MyAPI:
                def __init__(self):
                    self.counter = 0
                def greet(self, name):
                    return f"Hello, {name}!"
                def increment(self):
                    self.counter += 1

            api = MyAPI()
            cssl.share(api, "myapi")

            # Use in CSSL - changes are LIVE!
            cssl.exec('''
                ob <== $myapi;
                printl(ob.greet("World"));
                ob.increment();
                printl(ob.counter);  // 1
            ''')

            # Changes reflect back to Python!
            print(api.counter)  # 1

        Args:
            instance: Python object to share
            name: Name for the shared object (accessed as $name in CSSL)

        Returns:
            Path to the shared object marker file
        """
        global _live_objects
        runtime = self._get_runtime()

        # Handle argument order flexibility: share(instance, name) or share(name, instance)
        if name is None:
            # Only one argument - use object type as name
            name = type(instance).__name__
        elif isinstance(instance, str) and not isinstance(name, str):
            # Arguments are swapped: share("name", instance) -> swap them
            instance, name = name, instance
        elif not isinstance(name, str):
            # name is not a string - use its type as name
            name = type(name).__name__

        # Sanitize filename: remove invalid characters for Windows
        import re
        safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))

        # Initialize shared objects registry
        if not hasattr(runtime, '_shared_objects'):
            runtime._shared_objects = {}

        # Generate unique filename: <name>.shareobj<7digits>
        random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
        share_dir = _get_share_directory()
        filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"

        # Remove old file if updating
        if name in runtime._shared_objects:
            old_path = runtime._shared_objects[name]['path']
            try:
                Path(old_path).unlink(missing_ok=True)
            except Exception:
                pass

        # Store LIVE object reference in global registry
        _live_objects[name] = instance

        # Write marker file with metadata (not the actual object)
        import json
        metadata = {
            'name': name,
            'type': type(instance).__name__,
            'live': True,
            'id': id(instance)
        }
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(metadata, f)

        # Register in runtime
        runtime._shared_objects[name] = {
            'path': str(filepath),
            'type': type(instance).__name__,
            'live': True
        }

        # Also register the live proxy in the runtime's scope for $name access
        proxy = SharedObjectProxy(name, instance)
        runtime.global_scope.set(f'${name}', proxy)

        return str(filepath)

    def unshare(self, name: str) -> bool:
        """
        Remove a shared object.

        Args:
            name: Name of the shared object to remove

        Returns:
            True if removed, False if not found
        """
        global _live_objects
        runtime = self._get_runtime()

        if not hasattr(runtime, '_shared_objects'):
            return False

        if name not in runtime._shared_objects:
            return False

        # Remove from live objects registry
        if name in _live_objects:
            del _live_objects[name]

        # Remove from runtime scope
        try:
            runtime.global_scope.delete(f'${name}')
        except Exception:
            pass

        # Remove marker file
        filepath = runtime._shared_objects[name]['path']
        try:
            Path(filepath).unlink(missing_ok=True)
        except Exception:
            pass

        del runtime._shared_objects[name]
        return True

    def get_shared(self, name: str) -> Optional[Any]:
        """
        Get a shared object by name (for Python-side access).

        Returns the actual live object reference, not a copy.

        Args:
            name: Name of the shared object

        Returns:
            The live shared object or None if not found
        """
        global _live_objects

        # Return live object if available
        if name in _live_objects:
            return _live_objects[name]

        return None

    def shared(self, name: str) -> Optional[Any]:
        """
        Get a shared object by name (alias for get_shared).

        Returns the actual live object reference, not a copy.
        Works with both Python cssl.share() and CSSL ==> $name shared objects.

        Usage:
            from includecpp import CSSL
            cssl = CSSL.CsslLang()

            # Share an object
            my_obj = {"value": 42}
            cssl.share(my_obj, "data")

            # Retrieve it later
            obj = cssl.shared("data")
            print(obj["value"])  # 42

        Args:
            name: Name of the shared object (without $ prefix)

        Returns:
            The live shared object or None if not found
        """
        return self.get_shared(name)


# Global shared objects registry (for cross-instance sharing)
_global_shared_objects: Dict[str, str] = {}


def share(instance: Any, name: str = None) -> str:
    """
    Share a Python object globally for all CSSL instances (LIVE sharing).

    Changes made through CSSL will reflect back to the original object.

    Args can be passed in either order:
        share(my_object, "name")  # Preferred
        share("name", my_object)  # Also works
    """
    global _live_objects
    import re

    # Handle argument order flexibility
    if name is None:
        name = type(instance).__name__
    elif isinstance(instance, str) and not isinstance(name, str):
        instance, name = name, instance
    elif not isinstance(name, str):
        name = type(name).__name__

    # Sanitize filename
    safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))

    random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
    share_dir = _get_share_directory()
    filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"

    # Remove old file if updating
    if name in _global_shared_objects:
        try:
            Path(_global_shared_objects[name]).unlink(missing_ok=True)
        except Exception:
            pass

    # Store LIVE object reference
    _live_objects[name] = instance

    # Write marker file with metadata
    import json
    metadata = {
        'name': name,
        'type': type(instance).__name__,
        'live': True,
        'id': id(instance)
    }
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(metadata, f)

    _global_shared_objects[name] = str(filepath)
    return str(filepath)


def unshare(name: str) -> bool:
    """Remove a globally shared object."""
    global _live_objects

    if name not in _global_shared_objects:
        return False

    # Remove from live objects
    if name in _live_objects:
        del _live_objects[name]

    try:
        Path(_global_shared_objects[name]).unlink(missing_ok=True)
    except Exception:
        pass

    del _global_shared_objects[name]
    return True


def get_shared(name: str) -> Optional[Any]:
    """Get a globally shared object by name."""
    global _live_objects
    return _live_objects.get(name)


def shared(name: str) -> Optional[Any]:
    """
    Get a shared object by name (alias for get_shared).

    Works with both Python share() and CSSL ==> $name shared objects.

    Usage:
        from includecpp import CSSL

        # Share an object
        my_obj = {"value": 42}
        CSSL.share(my_obj, "data")

        # Retrieve it later
        obj = CSSL.shared("data")
        print(obj["value"])  # 42

    Args:
        name: Name of the shared object (without $ prefix)

    Returns:
        The live shared object or None if not found
    """
    return get_shared(name)


# Singleton for convenience
_default_instance: Optional[CsslLang] = None

def get_cssl() -> CsslLang:
    """Get default CSSL instance."""
    global _default_instance
    if _default_instance is None:
        _default_instance = CsslLang()
    return _default_instance


# Module-level convenience functions (v3.8.0 API)

def run(path_or_code: str, *args) -> Any:
    """
    Execute CSSL code or file.

    This is the primary method for running CSSL code in v3.8.0+.

    Usage:
        from includecpp import CSSL
        CSSL.run("script.cssl", arg1, arg2)
        CSSL.run("printl('Hello World');")

    Args:
        path_or_code: Path to .cssl file or CSSL code string
        *args: Arguments to pass to the script

    Returns:
        Execution result
    """
    return get_cssl().run(path_or_code, *args)


def exec(path_or_code: str, *args) -> Any:
    """
    Execute CSSL code or file.

    DEPRECATED: Use run() instead.
    """
    warnings.warn(
        "exec() is deprecated, use run() instead",
        DeprecationWarning,
        stacklevel=2
    )
    return get_cssl().run(path_or_code, *args)


def T_run(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
    """
    Execute CSSL code asynchronously in a thread.

    Usage:
        from includecpp import CSSL
        CSSL.T_run("async_script.cssl", arg1, callback=on_done)

    Args:
        path_or_code: Path to .cssl file or CSSL code string
        *args: Arguments to pass to the script
        callback: Optional callback when execution completes

    Returns:
        Thread object
    """
    return get_cssl().T_run(path_or_code, *args, callback=callback)


def T_exec(path_or_code: str, *args, callback: Optional[Callable[[Any], None]] = None) -> threading.Thread:
    """
    Execute CSSL code asynchronously in a thread.

    DEPRECATED: Use T_run() instead.
    """
    warnings.warn(
        "T_exec() is deprecated, use T_run() instead",
        DeprecationWarning,
        stacklevel=2
    )
    return get_cssl().T_run(path_or_code, *args, callback=callback)


def script(script_type: str, code: str, *params) -> CSSLScript:
    """
    Create a typed CSSL script.

    Usage:
        from includecpp import CSSL
        main = CSSL.script("cssl", '''printl("Main");''')
        payload = CSSL.script("cssl-pl", '''void helper() {}''')
        mod = CSSL.makemodule(main, payload, "mymod")

    Args:
        script_type: "cssl" for main script, "cssl-pl" for payload
        code: The CSSL code
        *params: Optional parameters

    Returns:
        CSSLScript object
    """
    return get_cssl().script(script_type, code, *params)


def load(path: str, name: str) -> None:
    """
    Load a .cssl or .cssl-pl file and register by name.

    Usage:
        CSSL.load("utils.cssl-pl", "utils")
        CSSL.execute("utils")
    """
    return get_cssl().load(path, name)


def execute(name: str, *args) -> Any:
    """
    Execute a previously loaded script by name.

    Usage:
        CSSL.load("utils.cssl-pl", "utils")
        result = CSSL.execute("utils", arg1, arg2)
    """
    return get_cssl().execute(name, *args)


def include(path: str, name: str) -> None:
    """
    Register a file for payload(name) access in CSSL.

    Usage:
        CSSL.include("helpers.cssl-pl", "helpers")
        CSSL.run('payload("helpers");')
    """
    return get_cssl().include(path, name)


def set_global(name: str, value: Any) -> None:
    """Set a global variable in CSSL runtime."""
    get_cssl().set_global(name, value)


def get_global(name: str) -> Any:
    """Get a global variable from CSSL runtime."""
    return get_cssl().get_global(name)


def get_output() -> List[str]:
    """Get output buffer from last execution."""
    return get_cssl().get_output()


def clear_output() -> None:
    """Clear output buffer."""
    get_cssl().clear_output()


# Aliases to avoid conflict with Python builtin exec
_run = run
_exec = exec
_T_run = T_run
_T_exec = T_exec


def module(code: str) -> CSSLModule:
    """
    Create a callable CSSL module from code.

    Usage:
        from includecpp import CSSL
        greet = CSSL.module('''
            printl("Hello, " + parameter.get(0) + "!");
        ''')
        greet("World")  # Prints "Hello, World!"

    Args:
        code: CSSL code string

    Returns:
        CSSLModule - a callable module
    """
    return get_cssl().module(code)


def makemodule(
    main_script: Union[str, CSSLScript],
    payload_script: Union[str, CSSLScript, None] = None,
    name: str = None
) -> CSSLFunctionModule:
    """
    Create a CSSL module with accessible functions.

    Usage (v3.8.0 - with CSSLScript):
        main = CSSL.script("cssl", '''printl("Main");''')
        payload = CSSL.script("cssl-pl", '''void helper() {}''')
        mod = CSSL.makemodule(main, payload, "mymod")

    Usage (legacy - code string):
        math_mod = CSSL.makemodule('''
            int add(int a, int b) { return a + b; }
        ''')
        math_mod.add(2, 3)  # Returns 5

    Args:
        main_script: Main CSSL code (string or CSSLScript)
        payload_script: Optional payload code (string or CSSLScript)
        name: Optional name to register for payload(name) access

    Returns:
        CSSLFunctionModule - module with callable function attributes
    """
    return get_cssl().makemodule(main_script, payload_script, name)


# Export all
__all__ = [
    'CsslLang',
    'CSSLModule',
    'CSSLScript',
    'CSSLFunctionModule',
    'get_cssl',
    # v3.8.0 primary API
    'run',
    '_run',
    'T_run',
    '_T_run',
    'script',
    'load',
    'execute',
    'include',
    # Legacy (deprecated)
    'exec',
    '_exec',
    'T_exec',
    '_T_exec',
    # Other
    'set_global',
    'get_global',
    'get_output',
    'clear_output',
    'module',
    'makemodule',
    'share',
    'unshare',
    'shared',
    'get_shared',
]
