from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Any

import yaml


@dataclass(frozen=True)
class CrewAITemplate:
    agents: dict[str, Any]
    tasks: dict[str, Any]
    workflow: dict[str, Any]
    tools_whitelist: set[str]


def _default_static_root() -> Path:
    return Path(__file__).resolve().parents[3] / "config" / "static" / "crewai"


def _read_yaml(file_path: Path) -> dict[str, Any]:
    if not file_path.is_file():
        raise FileNotFoundError(f"Required config file not found: {file_path}")
    with file_path.open("r", encoding="utf-8") as file:
        loaded = yaml.safe_load(file) or {}
    if not isinstance(loaded, dict):
        raise ValueError(f"YAML file must be a mapping: {file_path}")
    return loaded


def validate_workflow_stages(stages: list[str]) -> None:
    expected = ["intent", "execution", "organization"]
    if stages != expected:
        raise ValueError(f"Invalid workflow stages: {stages}, expected: {expected}")


def load_tools_whitelist(static_root: Path | None = None) -> set[str]:
    root = static_root or _default_static_root()
    tools = _read_yaml(root / "tools.yaml")
    raw_tools = tools.get("tools", [])
    if not isinstance(raw_tools, list):
        raise ValueError("tools.yaml field 'tools' must be a list")
    if not all(isinstance(item, str) and item.strip() for item in raw_tools):
        raise ValueError("tools.yaml list items must be non-empty strings")
    whitelist = {item.strip() for item in raw_tools}
    return whitelist


def load_crewai_template(static_root: Path | None = None) -> CrewAITemplate:
    root = static_root or _default_static_root()

    agents = _read_yaml(root / "agents.yaml")
    tasks = _read_yaml(root / "tasks.yaml")
    workflow = _read_yaml(root / "workflow.yaml")

    stages = workflow.get("stages")
    if not isinstance(stages, list):
        raise ValueError("workflow.yaml field 'stages' must be a list")
    validate_workflow_stages([str(stage) for stage in stages])

    return CrewAITemplate(
        agents=agents,
        tasks=tasks,
        workflow=workflow,
        tools_whitelist=load_tools_whitelist(root),
    )
