import json
import os

from backtesting import engine


def test_run_backtest_caches_by_input_file_signature(monkeypatch, tmp_path):
    history = tmp_path / "history.json"
    thresholds = tmp_path / "thresholds.json"
    weights = tmp_path / "weights.json"
    cache = tmp_path / "cache.json"
    for path in (history, thresholds, weights, cache):
        path.write_text("{}")

    monkeypatch.setattr(engine, "HISTORY_PATH", str(history))
    monkeypatch.setattr(engine, "_THRESH_PATH", str(thresholds))
    monkeypatch.setattr(engine, "ML_WEIGHTS_PATH", str(weights))
    monkeypatch.setattr(engine, "CACHE_PATH", str(cache))
    calls = []
    monkeypatch.setattr(
        engine, "_compute_backtest",
        lambda ml_mode=False: calls.append(ml_mode) or {"ml_mode": ml_mode, "calls": len(calls)},
    )
    engine.clear_backtest_cache()

    first = engine.run_backtest()
    second = engine.run_backtest()
    ml_first = engine.run_backtest(ml_mode=True)
    ml_second = engine.run_backtest(ml_mode=True)

    assert first == second == {"ml_mode": False, "calls": 1}
    assert ml_first == ml_second == {"ml_mode": True, "calls": 2}
    assert calls == [False, True]

    history.write_text('{"changed": true}')
    os.utime(history, None)
    invalidated = engine.run_backtest()
    assert invalidated == {"ml_mode": False, "calls": 3}


def test_cached_backtest_results_are_isolated_from_caller_mutation(monkeypatch, tmp_path):
    history = tmp_path / "history.json"
    history.write_text("{}")
    monkeypatch.setattr(engine, "HISTORY_PATH", str(history))
    monkeypatch.setattr(engine, "_THRESH_PATH", str(tmp_path / "missing-thresholds.json"))
    monkeypatch.setattr(engine, "ML_WEIGHTS_PATH", str(tmp_path / "missing-weights.json"))
    monkeypatch.setattr(engine, "CACHE_PATH", str(tmp_path / "missing-cache.json"))
    monkeypatch.setattr(engine, "_compute_backtest", lambda ml_mode=False: {"chart_data": [{"score": 10}]})
    engine.clear_backtest_cache()

    first = engine.run_backtest()
    first["chart_data"][0]["score"] = 99

    assert engine.run_backtest()["chart_data"][0]["score"] == 10
