from __future__ import annotations

if __package__ in {None, ""}:  # pragma: no cover - permite ejecución como script
    import sys
    from pathlib import Path

    _current_file = Path(__file__).resolve()
    for _parent in (_current_file.parent, *_current_file.parents):
        if (_parent / "pyproject.toml").exists() or (_parent / ".git").exists():
            _project_root = _parent
            break
    else:
        _project_root = _current_file.parents[2]
    _src_root = _project_root / "src"
    for _path in (_project_root, _src_root):
        _path_str = str(_path)
        if _path_str not in sys.path:
            sys.path.insert(0, _path_str)
    from agix._script_utils import bootstrap_script_environment

    bootstrap_script_environment("__main__", str(_current_file))

from typing import Any, Callable, Optional

from agix.agents.base import AGIAgent
from agix.control.controller_core import ControllerCore
from agix.evaluation.metrics import EvaluationMetrics


class AutoAgent:
    """Bucle de ejecución autónomo para un :class:`AGIAgent`."""

    def __init__(
        self,
        agent: AGIAgent,
        environment: Any,
        evaluator: Optional[Callable[[Any, Any, Any], dict]] = None,
        controller: Optional[ControllerCore] = None,
        metrics: Optional[type[EvaluationMetrics] | EvaluationMetrics] = None,
    ) -> None:
        self.agent = agent
        self.env = environment
        self.evaluator = evaluator
        self.controller = controller
        self.metrics = metrics or EvaluationMetrics
        self.reward_history: list[float] = []

    # ------------------------------------------------------------------
    def run(self, episodes: int = 1, max_steps: Optional[int] = None) -> dict[str, float]:
        """Ejecuta el bucle percepción-decisión-acción-aprendizaje."""
        for _ in range(episodes):
            observation = self.env.reset()
            done = False
            step = 0
            while not done and (max_steps is None or step < max_steps):
                self.agent.perceive(observation)
                action = self.agent.decide()
                observation, reward, done, _ = self.env.step(action)
                self.agent.learn(reward, done=done)

                success = None
                if self.evaluator:
                    try:
                        result = self.evaluator(observation, action, reward)
                        success = bool(result.get("exito"))
                    except Exception:
                        success = None
                try:
                    self.agent.record_experience(
                        str(observation), str(action), str(reward), success
                    )
                except Exception:
                    pass

                self.reward_history.append(reward)

                if self.controller:
                    try:
                        self.controller.ciclo_control(
                            percepcion=observation,
                            metas={},
                            retroalimentacion={
                                "reward": reward,
                                "states": [],
                                "actions": [],
                                "advantages": [],
                            },
                        )
                    except Exception:
                        pass
                step += 1
        return {
            "average_reward": self.metrics.average_reward(self.reward_history),
            "max_reward": self.metrics.max_reward(self.reward_history),
            "std_reward": self.metrics.std_reward(self.reward_history),
            "success_rate": self.metrics.success_rate(self.reward_history),
        }
