# Copyright (c) Metis. All rights reserved.

"""Algorithm compatibility engine for Mantis platform.

Matches agent capabilities against algorithm requirements to determine
which algorithms an agent can run.
"""

from __future__ import annotations

from typing import Any, Dict, List


def compute_compatible_algorithms(
    capabilities: List[str],
    algorithms: List[Dict[str, Any]],
) -> List[str]:
    """Match agent capabilities against algorithm requirements.

    An algorithm is compatible if the agent has all capabilities that the
    algorithm requires (boolean requirements set to True). Non-boolean
    requirements (e.g., min_runners: 1) are informational and don't gate
    compatibility — they're validated at verify/dry-run time.

    Args:
        capabilities: List of agent capability strings (e.g., ["tools", "gpu"]).
        algorithms: List of algorithm dicts, each with "name" and "requirements" keys.
            Can come from DB records or from Algorithm class metadata.

    Returns:
        List of compatible algorithm names.

    Example::

        algorithms = [
            {"name": "gepa", "requirements": {"gpu": False, "min_runners": 1}},
            {"name": "verl", "requirements": {"gpu": True}},
        ]
        compute_compatible_algorithms(["tools"], algorithms)
        # => ["gepa"]  (agent lacks "gpu" required by verl)

        compute_compatible_algorithms(["tools", "gpu"], algorithms)
        # => ["gepa", "verl"]
    """
    compatible: List[str] = []

    for algo in algorithms:
        reqs = algo.get("requirements", {})
        if not isinstance(reqs, dict):
            # No valid requirements → always compatible
            compatible.append(algo["name"])
            continue

        satisfied = True
        for key, value in reqs.items():
            if not isinstance(value, bool):
                continue  # non-boolean reqs are informational
            if not value:
                continue  # requirement is False → not required
            if key not in capabilities:
                satisfied = False
                break

        if satisfied:
            compatible.append(algo["name"])

    return compatible
