from __future__ import annotations
from typing import TYPE_CHECKING, Any
import uuid
if TYPE_CHECKING:
    from flownet.api.actor_method_ref import ActorMethodRef

    from flownet.compiler.flowtask import FlowTask
    

    

# 我们不是flink式的统一部署统一执行的。我们是灵活部署动态调度执行的。所以说transformation的内部算子是在构图之前就实例化的
class Transformation:
    def __init__(
        self,
        flowtask: FlowTask,
        rmf: ActorMethodRef,
        type: str = "map",
        *,
        operator_key: str | None = None,
        operator_config: dict | None = None,
    ):
        
        self.trans_id = uuid.uuid4().hex

        self.flowtask: FlowTask = flowtask
        self.type = type
        self.operator_key: str | None = operator_key
        self.operator_config: dict | None = operator_config
        # Transformation的类型，比如"map", "filter", "reduce"等
        self.target = rmf
            
        self.upstreams: list[Transformation] = []
        self.downstreams: list[Transformation] = []
        # 用来记录每一个下游transformation，以及对它而言的输入索引（用来处理多输入的情况）
        # Side-effect sink (terminal, no propagation).
        self.is_sink: bool = False
        # Return boundary for pipe/subflow semantics.
        self.is_return: bool = False
        # Optional hint for pipe() compile-time checks.
        self.pipe_flow: Any | None = None
        # Snapshot of exception handlers at build time (outer -> inner order).
        self.exception_handler_stack: list[ActorMethodRef | None] = []
        self._validate_target()
        self._validate_operator_key()
        self._validate_operator_config()

    def _validate_target(self) -> None:
        from flownet.api.actor_method_ref import ActorMethodRef
        from flownet.core.flow_program import FlowProgramRef
        from flownet.core.stateless import StatelessOpRef
        from flownet.core.exceptions import FlowDefinitionError

        if isinstance(self.target, (ActorMethodRef, StatelessOpRef, FlowProgramRef)):
            return
        raise FlowDefinitionError(
            "Flow graph accepts ActorMethodRef, StatelessOpRef, or FlowProgramRef."
        )

    def _validate_operator_key(self) -> None:
        if self.operator_key is None:
            return
        if not isinstance(self.operator_key, str) or not self.operator_key.strip():
            raise ValueError("operator_key must be a non-empty string when provided.")

    def _validate_operator_config(self) -> None:
        if self.operator_config is None:
            return
        if not isinstance(self.operator_config, dict):
            raise ValueError("operator_config must be a dict when provided.")
        
        
    def add_upstream(self, upstream_trans: Transformation):
        self.upstreams.append(upstream_trans)
        upstream_trans.downstreams.append(self)
