# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/classes/50_DomoCodeEngine.ipynb.

# %% auto 0
__all__ = ['DomoCodeEngine_ConfigError', 'ExportExtension', 'DomoCodeEngine_Function', 'DomoCodeEngine_Version',
           'DomoCodeEngine_Package']

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 2
from ..routes.codeengine import extract_functions, parse_javascript_before_functions, remove_javascript_comments

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 3
import os

from dataclasses import dataclass, field
from enum import Enum
from typing import List, Callable
import datetime as dt

import re

from io import open
import httpx

from nbdev.showdoc import patch_to

import domolibrary.client.DomoAuth as dmda

import domolibrary.routes.codeengine as codeengine_routes
import domolibrary.client.DomoError as de
import domolibrary.utils.files as dmuf
from domolibrary.utils.convert import convert_string_to_datetime
import domolibrary.classes.DomoUser as dmdu

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 7
class DomoCodeEngine_ConfigError(de.DomoError):
    def __init__(
        self,
        domo_instance,
        package_id,
        version=None,
        message=None,
        status=None,
        function_name=None,
    ):
        super().__init__(
            entity_id=package_id,
            message=f"verion {version} | {message}" if version else message,
            status=status,
            domo_instance=domo_instance,
            function_name=function_name,
        )


class ExportExtension(Enum):
    JAVASCRIPT = "js"
    PYTHON = "py"

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 8
@dataclass
class DomoCodeEngine_Function:
    name: str
    displayName: str
    description: str
    language: str
    package_id: str = field(repr=False)
    version: str = field(repr=False)

    code: str = None
    code_prefix : str = None
    orig_code: str = field(repr=False, default=None)
    inputs: List[dict] = field(repr=False, default=None)
    output: str = field(repr=False, default=None)
    example: str = field(repr=False, default=None)

    def __post_init__(self):
        self._set_code_prefix()
        
    def _set_code_prefix(self):
        if not self.orig_code:
            return None
        self.code_prefix = parse_javascript_before_functions(self.orig_code)
        

    @classmethod
    def _from_json(cls, obj, language, package_id, version, orig_code=None):
        return cls(
            **obj,
            language=language,
            orig_code=orig_code,
            package_id=package_id,
            version=version,
        )

    def __eq__(self, other):
        if not isinstance(other, DomoCodeEngine_Function):
            return False

        if (
            self.version != other.version
            or self.package_id != other.package_id
            or self.name != other.name
        ):
            return False

        return True

    def export(
        self, file_name: str = None, output_folder: str = None, debug_prn: bool = False
    ):

        output_folder = (
            f"EXPORT/{self.package_id}/{self.version}"
            if not output_folder
            else output_folder
        )

        output_folder = (
            f"{output_folder}/" if not output_folder.endswith("/") else output_folder
        )

        dmuf.upsert_folder(output_folder)

        file_name = file_name or self.name
        file_name = dmuf.change_extension(
            file_name, ExportExtension[self.language].value
        )

        file_path = os.path.join(output_folder, file_name)

        if debug_prn:
            print(output_folder, file_name)

        with open(file_path, "w+", newline="\n", encoding="utf-8") as f:
            if self.code_prefix:
                f.write(self.code_prefix)
            f.write(self.code)

        return file_path

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 9
@dataclass
class DomoCodeEngine_Version:
    auth: dmda.DomoAuth = field(repr=False)
    package_id: str
    version: str
    language: str
    description: str
    createdby_id: int
    released_dt: dt.datetime
    configuration: dict

    createdby: dmdu.DomoUser = None
    accounts_mapping: List[int] = None
    ml_model: List[str] = None

    code: str = field(repr=False, default=None)
    functions_ls: List[dict] = field(repr=False, default=None)
    functions: dict = None

    def _set_configuration(self, configuration=None):
        if configuration:
            self.configuration = configuration

        if not self.configuration:
            raise DomoCodeEngine_ConfigError(
                package_id=self.package_id,
                version=self.version,
                message="unable to set configuration",
                domo_instance=self.auth.domo_instance,
            )

        self.accounts_mapping = self.configuration["accountsMapping"]
        self.ml_model = self.configuration["mlModel"]

        return self

    def set_functions(
        self,
        code: str = None,
        functions: List[dict] = None,
        language: str = None,
        function_parser_fn: Callable = None,  # must receive code string, function_ls, language
    ):
        self.code = code or self.code

        self.functions_ls = functions or self.functions_ls

        self.language = language or self.language

        if not self.code or not self.configuration or not self.language:
            raise DomoCodeEngine_ConfigError(
                package_id=self.package_id,
                version=self.version,
                message="unable to set functions",
                domo_instance=self.auth.domo_instance,
            )
        try:
            function_parser_fn = function_parser_fn or extract_functions
            functions_ls = function_parser_fn(
                code=self.code, function_ls=self.functions_ls, language=self.language
            )

            self.functions = [
                DomoCodeEngine_Function._from_json(
                    obj,
                    orig_code=self.code,
                    language=self.language,
                    package_id=self.package_id,
                    version=self.version,
                )
                for obj in functions_ls
            ]
            return functions
        except Exception as e:
            print(e)
            raise DomoCodeEngine_ConfigError(
                package_id=self.package_id,
                version=self.version,
                message=e,
                domo_instance=self.auth.domo_instance,
            )

    @classmethod
    def _from_json(
        cls,
        obj: dict,
        package_id,
        auth: dmda.DomoAuth,
        language: str,
        supress_error: bool = True,
    ):

        domo_version = cls(
            auth=auth,
            package_id=package_id,
            language=language.upper() if language else None,
            version=obj["version"],
            code=obj.get("code"),
            description=obj.get("description", None),
            createdby_id=obj["createdBy"],
            released_dt=convert_string_to_datetime(obj.get("releasedOn")),
            configuration=obj["configuration"],
            functions_ls=obj["functions"],
        )

        try:
            domo_version._set_configuration()

        except DomoCodeEngine_ConfigError as e:
            if not supress_error:
                print(e)

        try:
            domo_version.set_functions()
        except DomoCodeEngine_ConfigError as e:
            if not supress_error:
                print(e)

        return domo_version

    @classmethod
    async def get_by_id_and_version(
        cls,
        package_id,
        version,
        auth: dmda.DomoAuth,
        language: str = None,
        debug_api: bool = False,
        debug_num_stacks_to_drop=2,
        return_raw: bool = False,
        session: httpx.AsyncClient = None,
    ):

        res = await codeengine_routes.get_codeengine_package_by_id_and_version(
            package_id=package_id,
            version=version,
            auth=auth,
            debug_api=debug_api,
            session=session,
            parent_class=cls.__name__,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )

        if return_raw:
            return res

        return cls._from_json(
            auth=auth, obj=res.response, package_id=package_id, language=language
        )

    def __eq__(self, other):
        if not isinstance(other, DomoCodeEngine_Version):
            return False

        if self.version != other.version or self.package_id != other.package_id:
            return False

        return True

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 13
@patch_to(DomoCodeEngine_Version)
def export(
    self,
    file_name: str = None,
    output_folder: str = "EXPORT/code_engine/",
    debug_prn: bool = False,
):
    output_folder = (
        f"{output_folder}/" if not output_folder.endswith("/") else output_folder
    )

    dmuf.upsert_folder(output_folder)

    file_name = file_name or self.package_id
    file_name = dmuf.change_extension(file_name, ExportExtension[self.language].value)

    file_path = os.path.join(output_folder, file_name)

    if debug_prn:
        print(output_folder, file_name)

    with open(file_path, "w+", newline="\n", encoding="utf-8") as f:
        f.write(self.code)

    return file_path

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 15
@dataclass
class DomoCodeEngine_Package:
    auth: dmda.DomoAuth = field(repr=False)
    id: str
    name: str
    description: str
    language: str
    environment: str
    availability: str
    owner_id: int
    created: dt.datetime
    last_modified: dt.datetime
    functions: List

    current_version: str = None
    versions: List[DomoCodeEngine_Version] = None
    owner: List[dmdu.DomoUser] = None

    def __post_init__(self):
        self._set_current_version()

    def _set_current_version(self):
        if not self.versions:
            return

        versions = [version.version for version in self.versions]
        self.current_version = max(versions)

    @classmethod
    def from_packages_api(cls, obj, auth):
        package_id = obj["id"]
        language = obj["language"]
        versions = [
            DomoCodeEngine_Version._from_json(
                version, package_id=package_id, language=language, auth=auth
            )
            for version in obj.get("versions")
        ]

        return cls(
            auth=auth,
            id=package_id,
            name=obj["name"],
            description=obj.get("description"),
            language=language,
            environment=obj.get("environment"),
            availability=obj.get("availability"),
            owner_id=obj.get("owner"),
            versions=versions,
            created=convert_string_to_datetime(obj.get("createdOn")),
            last_modified=convert_string_to_datetime(obj.get("updatedOn")),
            functions=obj.get("functions"),
        )

    @classmethod
    async def get_by_id(
        cls,
        auth: dmda.DomoAuth,
        package_id,
        debug_api: bool = False,
        session: httpx.AsyncClient = None,
        return_raw: bool = False,
        debug_num_stacks_to_drop=2,
    ):
        res = await codeengine_routes.get_codeengine_package_by_id(
            package_id,
            auth=auth,
            debug_api=debug_api,
            params=None,
            session=session,
            parent_class=cls.__name__,
            debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        )
        if return_raw:
            return res

        return cls.from_packages_api(res.response, auth=auth)

    def __eq__(self, other):
        if not isinstance(other, DomoCodeEngine_Package):
            return False

        if self.id != other.id:
            return False

        return True

# %% ../../nbs/classes/50_DomoCodeEngine.ipynb 17
@patch_to(DomoCodeEngine_Package, cls_method=True)
async def get_current_version_by_id(
    cls,
    auth: dmda.DomoAuth,
    package_id,
    debug_api: bool = False,
    session: httpx.AsyncClient = None,
    debug_num_stacks_to_drop=2,
):
    domo_package = await cls.get_by_id(
        package_id=package_id,
        auth=auth,
        debug_api=debug_api,
        session=session,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop,
    )

    current_version = domo_package.current_version

    domo_version = await DomoCodeEngine_Version.get_by_id_and_version(
        package_id=package_id,
        version=current_version,
        auth=auth,
        language=domo_package.language,
        debug_api=debug_api,
        debug_num_stacks_to_drop=debug_num_stacks_to_drop,
        session=session,
    )

    return domo_version
