#!/usr/bin/env python3
"""
将 V2 回测细节 JSON 转换为 HTML viewer 需要的 CSV 格式。

用途：
- 适配 backtest_viewer.html 的 CSV 格式要求
- 生成 _detail.csv、_close.csv、_holdings.csv、_code_info.csv

用法:
    python framework_v2/scripts/convert_to_viewer_csv.py
"""

import sys
import json
from pathlib import Path

import pandas as pd

project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))


def safe_float(val, decimals=4):
    """安全转换浮点数"""
    if val is None:
        return None
    try:
        return round(float(val), decimals)
    except (ValueError, TypeError):
        return None


def convert_v2_to_viewer_csv(json_path=None):
    """将 V2 JSON 转换为 V1 CSV 格式"""
    
    # 1. 加载 JSON
    if json_path is None:
        json_path = project_root / 'framework_v2' / 'results' / 'backtest_detail_v2.json'
    
    print(f"加载 V2 JSON: {json_path}")
    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    meta = data['meta']
    days = data['days']
    
    print(f"  天数: {len(days)}")
    print(f"  标的: {len(meta['codes'])}")
    
    # 2. 生成 _detail.csv
    print("\n生成 _detail.csv...")
    detail_rows = []
    
    for day in days:
        row = {
            '日期': day['date'],
            '净值': day['nav'],
            '日收益': day['daily_return'],
            '持仓标的': ','.join(day['holdings']) if day['holdings'] else ''
        }
        
        # 添加每个标的的动量
        for code, asset in day['assets'].items():
            row[f'动量_{code}'] = asset.get('momentum')
        
        detail_rows.append(row)
    
    detail_df = pd.DataFrame(detail_rows)
    detail_path = json_path.parent / 'backtest_detail_v2_detail.csv'
    detail_df.to_csv(detail_path, index=False, encoding='utf-8-sig')
    print(f"  ✅ {detail_path.name} ({len(detail_df)} 行)")
    
    # 3. 生成 _close.csv
    print("\n生成 _close.csv...")
    close_rows = []
    
    for day in days:
        row = {'日期': day['date']}
        
        for code, asset in day['assets'].items():
            # ETF 收盘价
            etf_close = asset.get('etf_close')
            row[f'收盘价_{code}'] = etf_close
        
        close_rows.append(row)
    
    close_df = pd.DataFrame(close_rows)
    close_path = json_path.parent / 'backtest_detail_v2_close.csv'
    close_df.to_csv(close_path, index=False, encoding='utf-8-sig')
    print(f"  ✅ {close_path.name} ({len(close_df)} 行)")
    
    # 4. 生成 _holdings.csv
    print("\n生成 _holdings.csv...")
    holdings_rows = []
    
    for day in days:
        if not day['holdings']:
            continue
        
        for code in day['holdings']:
            asset = day['assets'].get(code, {})
            
            code_meta = meta['codes'].get(code, {})
            
            row = {
                '日期': day['date'],
                '标的代码': code,
                '标的名称': code_meta.get('name', code),
                '大类': code_meta.get('group', ''),
                '进场日期': asset.get('entry_date'),
                '进场价': asset.get('entry_price'),
                '当前价': asset.get('etf_close'),
                '持仓天数': asset.get('holding_days', 0),
                '持仓比例': asset.get('weight', 0),
                '累计收益': asset.get('cum_return')
            }
            
            holdings_rows.append(row)
    
    holdings_df = pd.DataFrame(holdings_rows)
    holdings_path = json_path.parent / 'backtest_detail_v2_holdings.csv'
    holdings_df.to_csv(holdings_path, index=False, encoding='utf-8-sig')
    print(f"  ✅ {holdings_path.name} ({len(holdings_df)} 行)")
    
    # 5. 生成 _code_info.csv
    print("\n生成 _code_info.csv...")
    code_info_rows = []
    
    for code, meta_info in meta['codes'].items():
        row = {
            '代码': code,
            '名称': meta_info.get('name', code),
            '大类': meta_info.get('group', '')
        }
        code_info_rows.append(row)
    
    code_info_df = pd.DataFrame(code_info_rows)
    code_info_path = json_path.parent / 'backtest_detail_v2_code_info.csv'
    code_info_df.to_csv(code_info_path, index=False, encoding='utf-8-sig')
    print(f"  ✅ {code_info_path.name} ({len(code_info_df)} 行)")
    
    # 6. 汇总
    print("\n" + "=" * 80)
    print("转换完成！")
    print("=" * 80)
    print(f"\n输出文件:")
    print(f"  {detail_path.name}")
    print(f"  {close_path.name}")
    print(f"  {holdings_path.name}")
    print(f"  {code_info_path.name}")
    print(f"\n使用方法:")
    print(f"  1. 打开 visualization/backtest_viewer.html")
    print(f"  2. 选择 'V2 GlobalRotationStrategy (最新)'")
    print(f"  3. 自动加载 CSV 文件")


if __name__ == '__main__':
    convert_v2_to_viewer_csv()
