"""Tests for Factorminer pipeline integration with LocalFactorEvaluator."""

from __future__ import annotations

from typing import Dict, List, Optional, Tuple

import numpy as np
import pytest

from src.factorminer.core.factor_library import FactorLibrary
from src.factorminer.core.library_io import import_from_paper
from src.factorminer.evaluation.local_engine import LocalFactorEvaluator
from src.factorminer.evaluation.pipeline import (
    PipelineConfig,
    ValidationPipeline,
    run_evaluation_pipeline,
)
from src.factorminer.evaluation.runtime import (
    evaluate_factors_with_evaluator,
)


class TestLocalFactorEvaluatorIntegration:
    """测试 LocalFactorEvaluator 与评估管线的集成。"""

    @pytest.fixture
    def evaluator(self) -> LocalFactorEvaluator:
        """创建评估器 fixture。"""
        return LocalFactorEvaluator(
            start_date="20200101",
            end_date="20200131",
            stock_codes=None,
        )

    @pytest.fixture
    def returns_matrix(self) -> np.ndarray:
        """创建模拟收益率矩阵 fixture。"""
        M, T = 100, 20
        rng = np.random.default_rng(42)
        return rng.standard_normal((M, T))

    @pytest.fixture
    def splits(self) -> Dict[str, object]:
        """创建模拟分割 fixture。"""

        class MockSplit:
            def __init__(self, indices: np.ndarray, returns: np.ndarray):
                self.indices = indices
                self.returns = returns
                self.target_returns = {}

        T = 20
        indices = np.arange(T)
        rng = np.random.default_rng(42)
        returns = rng.standard_normal((100, T))

        return {
            "train": MockSplit(indices[:15], returns[:, :15]),
            "val": MockSplit(indices[15:], returns[:, 15:]),
        }

    def test_evaluate_factors_with_evaluator_deprecated_path(
        self,
        evaluator: LocalFactorEvaluator,
        returns_matrix: np.ndarray,
        splits: Dict[str, object],
    ) -> None:
        """测试 evaluate_factors_with_evaluator 在有 evaluator 时的行为。"""

        # 模拟一个因子对象
        class MockFactor:
            def __init__(self, id: str, name: str, formula: str, category: str):
                self.id = id
                self.name = name
                self.formula = formula
                self.category = category

        factors = [
            MockFactor("f1", "close", "close", "price"),
            MockFactor("f2", "# TODO: unsupported", "unsupported", "test"),
        ]

        try:
            artifacts = evaluate_factors_with_evaluator(
                factors=factors,
                evaluator=evaluator,
                returns=returns_matrix,
                splits=splits,
            )
            # 验证返回结果结构
            assert len(artifacts) == 2
            assert artifacts[0].name == "close"
            assert artifacts[1].name == "# TODO: unsupported"
            # unsupported 因子应该被标记
            assert artifacts[1].error == "Unsupported operator in formula"
        except Exception as e:
            # FactorEngine 可能因为数据不存在而失败
            pytest.skip(f"FactorEngine 数据不存在: {e}")

    def test_evaluate_factors_fallback_legacy(
        self,
        returns_matrix: np.ndarray,
        splits: Dict[str, object],
    ) -> None:
        """测试 evaluator=None 时回退到 legacy 方式。"""

        class MockFactor:
            def __init__(self, id: str, name: str, formula: str, category: str):
                self.id = id
                self.name = name
                self.formula = formula
                self.category = category

        factors = [
            MockFactor("f1", "test", "close", "price"),
        ]

        # evaluator=None 应该回退到 legacy
        artifacts = evaluate_factors_with_evaluator(
            factors=factors,
            evaluator=None,
            returns=returns_matrix,
            splits=splits,
        )
        # Legacy 方式会尝试 compute_tree_signals 但 data_dict 为空
        assert len(artifacts) == 1


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
