import torch
from .functional import functional
from .environment import Environment

def evolve(x, steps=100, lr=0.01, k=0.5, sigma=0.01, env_data=None):
    env = Environment(len(x), mode="data", data=env_data)

    history = []

    for t in range(steps):
        Phi, metrics = functional(x)

        Phi.backward()

        with torch.no_grad():
            E = env.generate(t)

            if not isinstance(E, torch.Tensor):
                E = torch.ones_like(x) * E

            F_env = k * (E - x)
            noise = sigma * torch.randn_like(x)

            x -= lr * x.grad
            x += F_env
            x += noise

            x.grad.zero_()

        history.append({
            "Phi": Phi.item(),
            "H": metrics["H"].item(),
            "I": metrics["I"].item(),
            "G": metrics["G"].item(),
            "env": E.mean().item()
        })

    return x, history
