"""Pipeline Loader - YAML 加载器"""

import logging
from pathlib import Path
from typing import Any

import yaml

from agentkit.orchestrator.pipeline_schema import Pipeline, PipelineStage

logger = logging.getLogger(__name__)


class PipelineLoader:
    """Pipeline YAML 加载器"""

    def __init__(self, pipelines_dir: str | Path | None = None):
        self._pipelines_dir = Path(pipelines_dir) if pipelines_dir else Path("pipelines")

    def load(self, pipeline_name: str) -> Pipeline:
        """从 YAML 文件加载 Pipeline"""
        yaml_path = self._pipelines_dir / f"{pipeline_name}.yaml"
        if not yaml_path.exists():
            yaml_path = self._pipelines_dir / f"{pipeline_name}.yml"
        if not yaml_path.exists():
            raise FileNotFoundError(f"Pipeline '{pipeline_name}' not found in {self._pipelines_dir}")

        content = yaml_path.read_text(encoding="utf-8")
        return self.load_from_yaml(content, pipeline_name)

    def load_from_yaml(self, yaml_content: str, pipeline_name: str | None = None) -> Pipeline:
        """从 YAML 字符串加载 Pipeline"""
        data = yaml.safe_load(yaml_content)

        stages = []
        for stage_data in data.get("stages", []):
            stages.append(PipelineStage(**stage_data))

        return Pipeline(
            name=data.get("name", pipeline_name or "unnamed"),
            version=data.get("version", "1.0.0"),
            description=data.get("description", ""),
            stages=stages,
            variables=data.get("variables", {}),
        )

    @staticmethod
    def validate_dag(stages: list[PipelineStage]) -> bool:
        """验证 DAG 无环"""
        stage_names = {s.name for s in stages}
        visited = set()
        path = set()

        def dfs(name: str) -> bool:
            if name in path:
                return False
            if name in visited:
                return True

            path.add(name)
            stage = next((s for s in stages if s.name == name), None)
            if stage:
                for dep in stage.depends_on:
                    if dep not in stage_names:
                        return False
                    if not dfs(dep):
                        return False
            path.remove(name)
            visited.add(name)
            return True

        return all(dfs(name) for name in stage_names)
