# src/backtest_runner.py

import pandas as pd
from datetime import datetime
from typing import List, Dict, Any, Optional, Type

# 导入核心组件
from .backtest_engine import BacktestEngine
from .data_manager import DataManager
from .execution_simulator import (
    ExecutionSimulator,
)  # 虽然不直接用，但 BacktestEngine 内部会用到
from .strategies.base_strategy import Strategy  # 用于类型提示
from .core_data import Bar, PortfolioSnapshot, Trade, Order  # 导入数据结构


def run_multi_segment_backtest(
    segment_configs: Dict[str, Dict[str, Any]],
    strategy_class: Type[Strategy],
    strategy_params: Dict[str, Any],
    initial_capital: float,
    slippage_rate: float,
    commission_rate: float,
    total_start_date: datetime,
    total_end_date: datetime,
) -> Dict[str, Any]:
    """
    运行一个多主力合约的分段回测，并返回合并后的回测结果。

    Args:
        segment_configs (Dict[str, Dict[str, Any]]): 包含所有合约片段配置的字典。
        strategy_class (Type[Strategy]): 要回测的策略类。
        strategy_params (Dict[str, Any]): 传递给策略的参数字典。
        initial_capital (float): 回测的初始资金。
        slippage_rate (float): 交易滑点率。
        commission_rate (float): 交易佣金率。
        total_start_date (datetime): 总回测的起始日期。
        total_end_date (datetime): 总回测的结束日期。

    Returns:
        Dict[str, Any]: 包含合并后的 portfolio_snapshots, trade_history, all_bars
                        和 initial_capital 的字典。
    """
    # --- 收集所有片段的回测结果 ---
    all_combined_snapshots: List[PortfolioSnapshot] = []
    all_combined_trades: List[Trade] = []
    all_combined_bars: List[Bar] = []

    # 用于净值平滑的基准值，从初始资金开始
    last_segment_adjusted_total_value = initial_capital
    current_cash = initial_capital  # 用于传递给下一个片段的初始资金
    current_positions: Dict[str, int] = {}  # 用于传递给下一个片段的初始持仓

    print("\n--- 开始分段回测跨越多个合约 ---")

    # 获取所有合约的有序键，确保按定义的顺序回测
    segment_keys = list(segment_configs.keys())

    for i, contract_symbol in enumerate(segment_keys):
        config = segment_configs[contract_symbol]
        segment_file = config["file"]
        segment_start_date = config["start"]
        segment_end_date = config["end"]

        current_segment_start = max(segment_start_date, total_start_date)
        current_segment_end = min(segment_end_date, total_end_date)

        if current_segment_start > current_segment_end:
            print(f"跳过片段 {contract_symbol}: 日期范围超出总回测周期或无效。")
            continue

        print(
            f"\n--- 回测片段: {contract_symbol} 从 {current_segment_start.strftime('%Y-%m-%d %H:%M')} 到 {current_segment_end.strftime('%Y-%m-%d %H:%M')} ---"
        )

        # 1. 初始化 DataManager (每个片段使用不同的 DataManager 实例)
        data_manager = DataManager(file_path=segment_file, symbol=contract_symbol)

        if data_manager.raw_df.empty:
            print(
                f"警告: 未能加载 {contract_symbol} 的数据文件 {segment_file}。跳过此片段。"
            )
            continue

        strategy_params["symbol"] = contract_symbol
        # 2. 创建 BacktestEngine 实例 (针对当前合约片段)
        engine = BacktestEngine(
            data_manager=data_manager,
            strategy_class=strategy_class,
            strategy_params=strategy_params,  # 使用传入的策略参数
            initial_capital=initial_capital,
            slippage_rate=slippage_rate,
            commission_rate=commission_rate,
            current_segment_symbol=contract_symbol,
        )

        # 在运行当前片段之前，将上一个片段结束时的资金和持仓注入到当前 BacktestEngine 的 simulator 中
        engine.get_simulator().reset(
            new_initial_capital=current_cash, new_initial_positions=current_positions
        )

        # 3. 运行当前片段回测
        engine.run_backtest()
        segment_results = engine.get_backtest_results()

        # 4. 获取当前片段结束后的最新资金和持仓状态，供下个片段使用
        current_cash = engine.get_simulator().cash
        current_positions = engine.get_simulator().positions.copy()

        # 5. 拼接结果：净值曲线需要特殊处理
        segment_snapshots = segment_results["portfolio_snapshots"]
        segment_trades = segment_results["trade_history"]
        segment_bars = segment_results["all_bars"]

        if segment_snapshots:
            first_snapshot_value_of_segment = segment_snapshots[0].total_value

            if first_snapshot_value_of_segment == 0:
                segment_relative_factor = 1.0
            else:
                segment_relative_factor = (
                    last_segment_adjusted_total_value / first_snapshot_value_of_segment
                )

            for snapshot in segment_snapshots:
                adjusted_snapshot_value = snapshot.total_value * segment_relative_factor
                adjusted_snapshot = PortfolioSnapshot(
                    datetime=snapshot.datetime,
                    total_value=adjusted_snapshot_value,
                    cash=snapshot.cash,
                    positions=snapshot.positions.copy(),
                    price_at_snapshot=snapshot.price_at_snapshot.copy(),
                )
                all_combined_snapshots.append(adjusted_snapshot)

            last_segment_adjusted_total_value = all_combined_snapshots[-1].total_value
        else:
            print(
                f"警告: 未能为 {contract_symbol} 生成任何快照。`last_segment_adjusted_total_value` 保持不变: {last_segment_adjusted_total_value:.2f}。"
            )

        all_combined_trades.extend(segment_trades)
        all_combined_bars.extend(segment_bars)

    print("\n--- 总分段回测完成 ---")

    return {
        "portfolio_snapshots": all_combined_snapshots,
        "trade_history": all_combined_trades,
        "all_bars": all_combined_bars,
        "initial_capital": initial_capital,  # 返回初始资金，方便 ResultAnalyzer 使用
    }


def run_backtest_for_optimization(
    global_config: Dict[str, Any],
    strategy_class: Type[Strategy],
    current_strategy_params: Dict[str, Any],
) -> Dict[str, Any]:
    """
    简化后的回测入口，用于优化或参数搜索。
    它从 global_config 中提取通用回测参数，并结合 current_strategy_params 运行回测。

    Args:
        global_config (Dict[str, Any]): 包含所有通用全局配置的字典。
        strategy_class (Type[Strategy]): 要回测的策略类。
        current_strategy_params (Dict[str, Any]): 当前迭代的策略参数。

    Returns:
        Dict[str, Any]: 包含合并后的 portfolio_snapshots, trade_history, all_bars
                        和 initial_capital 的字典。
    """
    total_start_date = global_config["total_start_date"]
    total_end_date = global_config["total_end_date"]
    initial_capital = global_config["initial_capital"]
    slippage_rate = global_config["slippage_rate"]
    commission_rate = global_config["commission_rate"]
    segment_configs = global_config["segment_configs"]

    return run_multi_segment_backtest(
        segment_configs=segment_configs,
        strategy_class=strategy_class,
        strategy_params=current_strategy_params,
        initial_capital=initial_capital,
        slippage_rate=slippage_rate,
        commission_rate=commission_rate,
        total_start_date=total_start_date,
        total_end_date=total_end_date,
    )
