import pickle

from tools import run_mlp_deep_sweep as sweep


def test_partition_candidate_ranges_is_balanced_and_exact():
    ranges = sweep.partition_candidate_ranges(11, 4)

    assert ranges == [(0, 3), (3, 6), (6, 9), (9, 11)]
    assert [idx for start, end in ranges for idx in range(start, end)] == list(range(11))


def test_pool_permission_error_uses_subprocess_shards(monkeypatch):
    candidates = [{"candidate": idx} for idx in range(3)]
    expected = [{"result": idx} for idx in range(3)]

    def deny_pool(**_kwargs):
        raise PermissionError(1, "not permitted")

    monkeypatch.setattr(sweep.concurrent.futures, "ProcessPoolExecutor", deny_pool)
    monkeypatch.setattr(
        sweep,
        "evaluate_candidates_subprocess",
        lambda tf, items, workers: (expected, workers),
    )

    results, workers = sweep.evaluate_candidates("8H", candidates, 3)

    assert results == expected
    assert workers == 3


def test_internal_shard_preserves_candidate_order(tmp_path, monkeypatch):
    input_path = tmp_path / "input.pkl"
    output_path = tmp_path / "output.pkl"
    candidates = [{"candidate": 2}, {"candidate": 3}]
    payload = {
        "version": 1,
        "asset": "COINBASE_BTCUSD",
        "tf": "8H",
        "ordinal": 1,
        "start": 2,
        "end": 4,
        "candidates": candidates,
    }
    with input_path.open("wb") as handle:
        pickle.dump(payload, handle)

    monkeypatch.setattr(
        sweep,
        "evaluate_candidates_sequential",
        lambda tf, items, show_progress=False: [
            {"result": item["candidate"]} for item in items
        ],
    )

    sweep.run_internal_shard("8H", input_path, output_path)

    with output_path.open("rb") as handle:
        output = pickle.load(handle)
    assert output["start"] == 2
    assert output["end"] == 4
    assert output["results"] == [{"result": 2}, {"result": 3}]
