# coding: utf-8


from idm.core.constants.system import SYSTEM_WORKFLOW_EXECUTION_METHOD
from idm.core.constants.workflow import RUN_REASON, REQUEST_TYPE
from idm.core.workflow.plain.executors import PlainWorkflowExecutor
from idm.core.workflow.plain.group import groupify as plain_groupify
from idm.core.workflow.plain.user import userify as plain_userify
from idm.core.workflow.sandbox.manager.executors import SandboxedUserWorkflowExecutor, SandboxedGroupWorkflowExecutor
from idm.core.workflow.common.subject import subjectify


def workflow(
    code, role_data=None, system=None, requester=None, subject=None, node=None, ignore_approvers=False,
    execution_method=None, **kwargs):
    subject = subjectify(subject)
    executor = subject.get_executor_class(system, node, execution_method)(code, system)
    kwargs.update(subject.get_role_kwargs())
    context = executor.run(role_data=role_data, system=system, requester=requester, node=node,
                           ignore_approvers=ignore_approvers, **kwargs)
    return context


def workflow_check(workflow_text, role_data=None, system=None, requester=None,
                   subject=None, node=None, expected_fields=None, **kwargs):
    """Функция для тестирования workflow в доктестах.

    Принимает запрашивающего, того для кого запрашивается роль и
    саму роль (в виде словарика).
    Возвращает список аппруверов.
    """
    subject = subjectify(subject)
    executor = subject.get_executor_class(system, node)(workflow_text, system)
    kwargs.update(subject.get_role_kwargs())
    message = executor.run_catch_exceptions(
        role_data=role_data, system=system, requester=requester, node=node,
        reason=RUN_REASON.DOCTEST, expected_fields=expected_fields, **kwargs
    )
    return message


def run_doctests(code, system, **kwargs):
    # Запускается в случае plain способа запуска workflow
    assert system.workflow_execution_method == SYSTEM_WORKFLOW_EXECUTION_METHOD.PLAIN
    executor = PlainWorkflowExecutor(code, system)
    return executor.run_doctests(**kwargs)


def run_doctests_check(workflow_text, system, user_workflow=True):
    """Прогоняет doctest для проверки целостности workflow"""
    def run(requester, user, role, expected_fields=None, **kwargs):
        from idm.core.models import RoleNode
        node = RoleNode.objects.get_node_by_data(system, role)
        return workflow_check(workflow_text, role, system, requester, user,
                              node=node, expected_fields=expected_fields, **kwargs)

    if system.workflow_execution_method == SYSTEM_WORKFLOW_EXECUTION_METHOD.PLAIN:
        userify = plain_userify
        groupify = plain_groupify

        return run_doctests(
            workflow_text,
            system,
            run=run,
            user=userify,
            group=groupify,
        )
    elif system.workflow_execution_method == SYSTEM_WORKFLOW_EXECUTION_METHOD.SANDBOXED:
        if user_workflow:
            executor = SandboxedUserWorkflowExecutor(workflow_text, system)
        else:
            executor = SandboxedGroupWorkflowExecutor(workflow_text, system)
        return executor.run_doctests()
    else:
        raise ValueError('Invalid workflow execution method ({})'.format(system.workflow_execution_method))
