"""Asset selection must pair the same asset's chart and winner paths.

The stale-global regression uses temporary files so private chart exports are
not needed. Winner path checks use the repository's tracked winner fixtures.
"""
import os

import pytest

import tools.mlp_results_table as mrt

REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

NON_BTC_ASSET = "COINBASE_ETHUSD"  # has real winner CSVs, no real price data


class TestTfMap:
    """`_tf_map(asset)` must build asset-specific paths, not just BTC ones."""

    def test_returns_a_path_per_configured_timeframe(self):
        tf_map = mrt._tf_map(NON_BTC_ASSET)
        assert set(tf_map.keys()) == set(mrt._TF_PERIODS.keys())

    @pytest.mark.parametrize("tf,period", list(mrt._TF_PERIODS.items()))
    def test_path_embeds_the_requested_asset_and_period(self, tf, period):
        tf_map = mrt._tf_map(NON_BTC_ASSET)
        assert tf_map[tf] == f"data/mlp/{NON_BTC_ASSET}, {period}.csv"

    def test_different_assets_never_collide(self):
        btc = mrt._tf_map("COINBASE_BTCUSD")
        eth = mrt._tf_map(NON_BTC_ASSET)
        for tf in mrt._TF_PERIODS:
            assert btc[tf] != eth[tf]


class TestWinnerPath:
    """`winner_path(tf, asset)` must resolve to the real on-disk winner CSV."""

    @pytest.mark.parametrize("tf", ["4H", "6H", "8H", "12H", "1D"])
    def test_explicit_non_btc_asset_resolves_to_a_file_that_exists(self, tf):
        wp = mrt.winner_path(tf, NON_BTC_ASSET)
        assert wp == mrt.WINNER_DIR / f"optimization_winner_strategy_mlp_scores_{NON_BTC_ASSET}_{tf}.csv"
        abs_wp = os.path.join(REPO_ROOT, str(wp))
        assert os.path.exists(abs_wp), f"expected real fixture at {abs_wp}"

    def test_default_asset_falls_back_to_module_global(self, monkeypatch):
        monkeypatch.setattr(mrt, "ASSET", NON_BTC_ASSET)
        assert mrt.winner_path("4H") == mrt.winner_path("4H", NON_BTC_ASSET)


class TestGlobalPairingHazard:
    """
    The real hazard: ASSET and TF_MAP are independent mutable globals.
    main() pairs them correctly; a direct caller of evaluate_tf() need not.
    """

    def test_mains_paired_reassignment_keeps_asset_and_tf_map_in_sync(self, monkeypatch):
        # Given: simulate exactly what main() does for a non-BTC --asset,
        # i.e. reassign both globals together.
        monkeypatch.setattr(mrt, "ASSET", NON_BTC_ASSET)
        monkeypatch.setattr(mrt, "TF_MAP", mrt._tf_map(NON_BTC_ASSET))

        # Then: every TF's data-file entry and winner path agree on the asset.
        for tf in mrt._TF_PERIODS:
            assert NON_BTC_ASSET in mrt.TF_MAP[tf]
            assert NON_BTC_ASSET in str(mrt.winner_path(tf))

    def test_evaluate_tf_never_pairs_one_assets_data_with_anothers_winner(self, monkeypatch, tmp_path):
        # Build the stale-data trap without a private export dependency.
        monkeypatch.chdir(tmp_path)
        monkeypatch.setattr(mrt, "ASSET", NON_BTC_ASSET)
        stale_data_file = tmp_path / mrt.TF_MAP["4H"]
        stale_data_file.parent.mkdir(parents=True)
        stale_data_file.write_text("time,close,high\n1609459200,100,100\n")
        winner_dir = tmp_path / 'winners'
        winner_dir.mkdir()
        monkeypatch.setattr(mrt, 'WINNER_DIR', winner_dir)
        mrt.winner_path('4H').write_text('mlp_weights_file\nfake.json\n')
        # Wrong pairing would read this existing BTC file then reach signals.
        monkeypatch.setattr(mrt.strat, 'generate_signals',
                            lambda *args, **kwargs: pytest.fail('mixed asset data'))
        assert mrt.evaluate_tf("4H") is None

    def test_evaluate_tf_ignores_tf_map_entirely_for_an_explicit_asset(self, monkeypatch, tmp_path):
        monkeypatch.chdir(tmp_path)
        # Given: TF_MAP is left pointing at a completely unrelated asset.
        monkeypatch.setattr(mrt, "TF_MAP", {"4H": "does/not/exist.csv"})

        # When/Then: passing asset explicitly must not consult TF_MAP at all —
        # it still fails safe on the (real, expected) missing ETHUSD data file,
        # not on the bogus TF_MAP path.
        result = mrt.evaluate_tf("4H", asset=NON_BTC_ASSET)
        assert result is None
