from functools import cached_property
import shlex
import subprocess
from wizlib.parser import WizParser
from yaml import safe_load, safe_dump

from dyngle.command import DyngleCommand
from dyngle.model.context import Context
from dyngle.model.expression import expression
from dyngle.model.template import Template
from dyngle.error import DyngleError


class RunCommand(DyngleCommand):
    """Run a workflow defined in the configuration"""

    name = "run"

    @classmethod
    def add_args(cls, parser: WizParser):
        super().add_args(parser)
        parser.add_argument(
            "operation", help="Operation name to run", nargs="?"
        )
        parser.add_argument(
            "args", nargs="*", help="Optional operation arguments"
        )
        parser.add_argument(
            "--display",
            choices=["steps", "none"],
            default="steps",
            help="Display option for operation execution (default: steps)"
        )

    def handle_vals(self):
        super().handle_vals()
        keys = self.app.dyngleverse.operations.keys()
        if not self.provided("operation"):
            self.operation = self.app.ui.get_text("Operation: ", sorted(keys))
            if not self.operation:
                raise DyngleError(f"Operation required.")
        if self.operation not in keys:
            raise DyngleError(f"Invalid operation {self.operation}.")

    @DyngleCommand.wrap
    def execute(self):
        data_string = self.app.stream.text
        data = safe_load(data_string) or {}
        operation = self.app.dyngleverse.operations[self.operation]
        return_value = operation.run(
            Context(data), self.args, display=self.display
        )
        self.status = f'Operation "{self.operation}" completed successfully'
        
        # Print return value if present
        if return_value is not None:
            output = self._format_return_value(return_value)
            return output
    
    def _format_return_value(self, value):
        """Format return value for output.
        
        Dicts and lists are formatted as YAML.
        Other types are converted to string.
        """
        if isinstance(value, (dict, list)):
            yaml_output = safe_dump(value, default_flow_style=False)
            return yaml_output.rstrip()
        else:
            return str(value)
