# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/routes/codeengine.ipynb.

# %% auto 0
__all__ = ['CodeEngine_Package_Parts', 'remove_javascript_comments', 'parse_javascript_between_functions',
           'parse_javascript_between_module', 'remove_after_closing_parens', 'parse_javascript', 'parse_python',
           'parse_functions_factory', 'extract_functions']

# %% ../../nbs/routes/codeengine.ipynb 2
import httpx

from enum import Enum, auto
from typing import  List, Callable
from functools import partial

import re

import domolibrary.client.get_data as gd
import domolibrary.client.ResponseGetData as rgd
import domolibrary.client.DomoAuth as dmda


# %% ../../nbs/routes/codeengine.ipynb 4
class CodeEngine_Package_Parts(Enum):
    VERSIONS = auto()
    FUNCTIONS=  auto()
    CODE = auto()
    

# %% ../../nbs/routes/codeengine.ipynb 5
@gd.route_function
async def get_codeengine_package_by_id(
    package_id,
    auth: dmda.DomoAuth,
    debug_api: bool = False,
    params : dict = None,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
) -> rgd.ResponseGetData:
    url = f"https://{auth.domo_instance}.domo.com/api/codeengine/v2/packages/{package_id}"

    params = params or {
        'parts' : "versions"
    }
    
    return await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        debug_api=debug_api,
        params = params,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

# %% ../../nbs/routes/codeengine.ipynb 7
@gd.route_function
async def get_codeengine_package_by_id_and_version(
    package_id,
    version,
    auth: dmda.DomoAuth,
    debug_api: bool = False,
    params : dict = None,
    session: httpx.AsyncClient = None,
    parent_class: str = None,
    debug_num_stacks_to_drop=1,
) -> rgd.ResponseGetData:
    url = f"https://{auth.domo_instance}.domo.com/api/codeengine/v2/packages/{package_id}/versions/{version}"

    params = params or {
        'parts' : "functions,code"
    }
    
    return await gd.get_data(
        auth=auth,
        url=url,
        method="GET",
        debug_api=debug_api,
        params = params,
        session=session,
        parent_class=parent_class,
        num_stacks_to_drop=debug_num_stacks_to_drop,
    )

# %% ../../nbs/routes/codeengine.ipynb 11
def remove_javascript_comments(code, **kwargs):
    pattern = r"(/\*\*(.*?)\*/)"
    return re.sub(pattern, "", code, flags=re.DOTALL)
    
def parse_javascript_between_functions(code, function_name):
    pattern = r"((async\s)?function\s+" + function_name + r"\(.*?\).*?)(?=function)"
    match = re.search(pattern, code, re.DOTALL)
    return match.group(0) if match else None

def parse_javascript_between_module(code,function_name):
    pattern = r"((async\s)?function\s+" + function_name + r"\(.*?\).*?)(?=module.export)"
    match = re.search(pattern, code, re.DOTALL)
    return match.group(0) if match else None

def remove_after_closing_parens(code, **kwargs):
    pattern = r"(.*\})"
    match = re.search(pattern, code, re.DOTALL)
    return match.group(0) if match else None

def parse_javascript(function_name, code):
    #remove comments
    code = remove_javascript_comments(code)

    # find everything until the next function definition
    match_str = parse_javascript_between_functions(code= code, function_name = function_name)

    if not match_str:
        match_str = parse_javascript_between_module(code = code, function_name= function_name)

    # remove everything after the last closing parens
    return remove_javascript_comments(match_str)

def parse_python(function_name, code):
    pattern = (
        r"(async\s+)?def\s+"
        + re.escape(function_name)
        + r'\s*\([^)]*\)\s*:\s*[^}]*'
    )
    match = re.search(pattern, code, re.DOTALL)
    return match.group(0)

class parse_functions_factory(Enum):
    PYTHON = partial(parse_python)
    JAVASCRIPT = partial(parse_javascript)

def extract_functions(
        function_ls : List[dict], # from API, function metadata
        code : str, # from API, code string 
        language: str, # PYTHON or JAVASCRIPT, must align with parse_functions_factory enum
        parse_fn: Callable = None # function for exctracting functions must receive `code:str` and function_name:str`
        ):
    
    """helper function that handles parsing """

    parse_fn = parse_fn or parse_functions_factory[language]

    res = []

    # return [{ **function, "code" : parse_fn.value(function_name=function["name"], code=code)}
    #     for function in function_ls
    # ]
    for function in function_ls: 
        function_name = function['name']
        # print(function_name)
        code_obj = {"code" : parse_fn.value(function_name=function_name, code = code)}
        # print(code_obj)
        res.append({ **function, **code_obj})
        
    return res

