# Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import uuid

from st2common import log as logging
from st2common.constants.action import LIVEACTION_STATUS_SUCCEEDED
from st2common.constants.action import LIVEACTION_STATUS_FAILED
from st2common.constants.action import LIVEACTION_STATUS_PENDING
from st2common.constants.triggers import INQUIRY_TRIGGER
from st2common.models.system.common import ResourceReference
from st2common.runners.base import ActionRunner
from st2common.services import action as action_service
from st2common.transport.reactor import TriggerDispatcher
from st2common.util import action_db as action_utils

LOG = logging.getLogger(__name__)

__all__ = [
    'get_runner',
    'Inquirer',
]

# constants to lookup in runner_parameters.
RUNNER_SCHEMA = 'schema'
RUNNER_ROLES = 'roles'
RUNNER_USERS = 'users'
RUNNER_TAG = 'tag'


def get_runner():
    'RunnerTestCase',
    return Inquirer(str(uuid.uuid4()))


class Inquirer(ActionRunner):
    """This runner implements the ability to ask for more input during a workflow
    """

    def __init__(self, runner_id):
        super(Inquirer, self).__init__(runner_id=runner_id)
        self.trigger_dispatcher = TriggerDispatcher(LOG)

    def pre_run(self):
        super(Inquirer, self).pre_run()

        # TODO :This is awful, but the way "runner_parameters" and other variables get
        # assigned on the runner instance is even worse. Those arguments should
        # be passed to the constructor.
        self.schema = self.runner_parameters.get(RUNNER_SCHEMA, None)
        self.roles_param = self.runner_parameters.get(RUNNER_ROLES, None)
        self.users_param = self.runner_parameters.get(RUNNER_USERS, None)
        self.tag = self.runner_parameters.get(RUNNER_TAG, None)

    def run(self, action_parameters):

        # Retrieve existing result (initialize if needed)
        liveaction_db = action_utils.get_liveaction_by_id(self.liveaction_id)
        response_data = liveaction_db.result.get("response_data", {})

        # Request pause of parent execution
        parent = liveaction_db.context.get("parent")
        if parent:
            # TODO get current user
            action_service.request_pause(parent, "st2admin")
        else:
            LOG.error("Inquiries must be run within a workflow.")
            return (LIVEACTION_STATUS_FAILED, response_data, None)

        # Validate repsonse and return
        if action_service.validate_response(self.schema, response_data):
            return (LIVEACTION_STATUS_SUCCEEDED, response_data, None)
        else:
            trigger_ref = ResourceReference.to_string_reference(
                pack=INQUIRY_TRIGGER['pack'],
                name=INQUIRY_TRIGGER['name']
            )
            trigger_payload = {
                "liveaction_id": self.liveaction_id,
                "response": response_data,
                "schema": self.schema,
                "roles": self.roles_param,
                "users": self.users_param,
                "tag": self.tag
            }
            self.trigger_dispatcher.dispatch(trigger_ref, trigger_payload)
            return (LIVEACTION_STATUS_PENDING, response_data, None)

@@ -2525,66 +2525,8 @@
 ):%0A%0A
-        # Retrieve existing result (initialize if needed)%0A
     
@@ -2594,24 +2594,72 @@
 veaction_id)
+%0A%0A        # Retrieve existing response if exists
 %0A        res
@@ -2734,557 +2734,495 @@
 # Re
-quest pause of parent execution%0A        parent = liveaction_db.context.get(%22parent%22)%0A        if parent:%0A            # TODO get current user%0A            action_service.request_pause(parent, %22st2admin%22)%0A        else:%0A            LOG.error(%22Inquiries must be run within a workflow.%22)%0A            return (LIVEACTION_STATUS_FAILED, response_data, None)%0A%0A        # Validate repsonse and return%0A        if action_service.validate_response(self.schema, response_data):%0A            return (LIVEACTION_STATUS_SUCCEEDED, response_data, None)%0A        else:%0A    
+turn immediately if response is already valid%0A        if action_service.validate_response(self.schema, response_data):%0A            return (LIVEACTION_STATUS_SUCCEEDED, response_data, None)%0A%0A        # Fail if there is no parent execution%0A        parent = liveaction_db.context.get(%22parent%22)%0A        if not parent:%0A            LOG.error(%22Inquiries must be run within a workflow.%22)%0A            return (LIVEACTION_STATUS_FAILED, response_data, None)%0A%0A        # Assemble and dispatch trigger%0A
     
@@ -3290,20 +3290,16 @@
         
-    
 pack=INQ
@@ -3332,20 +3332,16 @@
         
- 
-   
 name=INQ
@@ -3373,18 +3373,10 @@
     
-   
- 
 )%0A
-    
     
@@ -3399,20 +3399,16 @@
 oad = %7B%0A
-    
         
@@ -3448,20 +3448,16 @@
 ion_id,%0A
-    
         
@@ -3499,20 +3499,16 @@
         
-    
 %22schema%22
@@ -3534,20 +3534,16 @@
         
-   
- 
 %22roles%22:
@@ -3553,36 +3553,32 @@
 lf.roles_param,%0A
-    
             %22use
@@ -3612,20 +3612,16 @@
         
- 
-   
 %22tag%22: s
@@ -3640,18 +3640,10 @@
     
-    %7D%0A    
+%7D%0A
     
@@ -3709,20 +3709,246 @@
 ayload)%0A
+%0A
     
+    # Request pause as final step before returning (to ensure other logic works)%0A        action_service.request_pause(parent, self.context.get('user', None))%0A%0A        # TODO there's an issue here, because response_data is %7B%7D%0A
         

Reorder logic so that request_pause is last