from __future__ import annotations

from abc import ABC, abstractmethod
from enum import Enum
from typing import Any, Mapping, Optional


class EngineCapability(str, Enum):
    VALIDATE = "validate"
    DEPLOY_DISABLED = "deploy_disabled"
    ACTIVATE = "activate"
    DEACTIVATE = "deactivate"
    EXECUTE = "execute"
    PAUSE = "pause"
    KILL = "kill"
    REPLAY = "replay"
    BACKFILL = "backfill"
    GET_EXECUTION = "get_execution"
    GET_LOGS = "get_logs"


class EngineCapabilityUnsupported(RuntimeError):
    def __init__(self, engine: str, operation: str, reason: str = ""):
        message = f"{engine} does not support {operation}"
        if reason:
            message = f"{message}: {reason}"
        super().__init__(message)
        self.engine = engine
        self.operation = operation
        self.reason = reason


class WorkflowEngine(ABC):
    engine_name: str
    capabilities: frozenset[EngineCapability]

    @abstractmethod
    def validate(self, definition: Any) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def deploy_disabled(self, definition: Any) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def activate(self, namespace: str, definition_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def deactivate(self, namespace: str, definition_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def execute(
        self,
        namespace: str,
        definition_id: str,
        inputs: Optional[Mapping[str, Any]] = None,
        **options: Any,
    ) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def pause(self, execution_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def kill(self, execution_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def replay(self, execution_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def backfill(
        self,
        namespace: str,
        definition_id: str,
        trigger_id: str,
        start: str,
        end: Optional[str],
    ) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def get_execution(self, execution_id: str) -> Mapping[str, Any]:
        raise NotImplementedError

    @abstractmethod
    def get_logs(self, execution_id: str) -> Any:
        raise NotImplementedError
