from typing import Set
from radiuma_api.task import Task, Status
from radiuma_api.execution_context import ExecutionContext
# Write Codes Here:


class Scheduler:
    """
    DAG-based execution scheduler.
    Decides WHEN a Task can run based on port readiness and orchestrates execution.
    """

    def __init__(self):
        self._completed: Set[Task] = set()
        self._failed: Set[Task] = set()

    def run(self, root: Task, context: ExecutionContext):
        """
        Entry point: execute a Workflow or Task graph.
        """
        self._execute_task(root, context)

    def _execute_task(self, task: Task, context: ExecutionContext):
        """
        Execute a task respecting DAG dependencies.
        If 'task' is a Workflow (has children), delegate to _run_workflow.
        Otherwise, run the leaf task when inputs are ready.
        """
        # Skip finished tasks
        if task.status in (Status.COMPLETED, Status.FAILED, Status.STOPPED):
            return

        # Workflow (composite)
        if hasattr(task, "children"):
            self._run_workflow(task, context)
            return

        # Leaf Task: must have inputs ready
        if not task.check_inputs_ready(context):
            # Optional: diagnostic log
            print(f"[Scheduler] Task '{task.name}' not ready, skipping for now.")
            return

        try:
            task._set_status(Status.RUNNING)
            task.run(context)
            task._set_status(Status.COMPLETED)
            self._completed.add(task)
        except Exception as e:
            task._set_status(Status.FAILED)
            self._failed.add(task)
            # Optional: diagnostic log
            print(f"[Scheduler] Task '{task.name}' failed: {e}")
            # Re-raise to surface error if caller needs to handle
            raise

    def _run_workflow(self, workflow: Task, context: ExecutionContext):
        """
        Execute children respecting dependencies.
        Progress until all children are executed or a deadlock is detected.
        """
        workflow._set_status(Status.RUNNING)

        remaining = set(workflow.children)

        while remaining:
            progress_made = False

            for child in list(remaining):
                if child.check_inputs_ready(context):
                    self._execute_task(child, context)
                    remaining.remove(child)
                    progress_made = True

            if not progress_made:
                # Deadlock: dependencies not resolvable with current data
                raise RuntimeError(
                    f"Workflow '{workflow.name}' deadlock: unresolved dependencies"
                )

        # Final workflow status based on children results
        if any(c.status == Status.FAILED for c in workflow.children):
            workflow._set_status(Status.FAILED)
        else:
            workflow._set_status(Status.COMPLETED)
