from abc import ABC, abstractmethod
from collections.abc import Callable
from logging import Logger
from typing import Any, TypeAlias

from pydantic import BaseModel

from test_automation_suite.core.context import Context
from test_automation_suite.dependencies.dependency import Dependency


class StepResult(BaseModel):
    """Result state of a single step"""

    success: bool
    """Whether the step completed successfully."""

    abort_on_failure: bool = True
    """When success is false, the task will not continue."""

    needs_reboot: bool = False
    """A reboot will be done before the next task can run."""

    harvest_data: dict[str, Any] = {}
    """Either some values like FPS medians etc. or paths to artifacts."""


Step: TypeAlias = Callable[[Context, Logger], StepResult]
"""One step of a task

This is simply a type alias for a function of the form `(Context) -> StepResult`.
"""


class TaskResult(BaseModel):
    success: bool
    log: list[str]

    # TODO: test tasks that generate artifacts (there are none yet)
    harvest_data: dict[str, Any]
    """Either some values like FPS medians etc. or paths to artifacts"""


class Task(BaseModel, ABC):
    def dependencies(self) -> list[Dependency]:
        """Returns a list of dependencies which must be installed before the task can run"""
        return []

    @abstractmethod
    def steps(self) -> list[Step]:
        return []
