"""
Task 2: 收益计算问题诊断

分析维度：
2.1 首日 NAV 检查 - 逻辑瑕疵
2.2 T+1 执行偏差 - 跨市场 ETF 的 open-to-close 收益分布
2.3 溢价率影响分析 - QDII ETF 高溢价时的买入后果
"""

import ast
import sys
from pathlib import Path
from collections import defaultdict
from typing import List, Dict

import numpy as np
import pandas as pd

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

from rotation.experiments.common import (
    load_nav, load_signals, load_detail_days, load_detail_meta,
    print_section,
)

# 跨市场 ETF 映射
CROSS_MARKET_ETFS = {
    'NDX': '513100.SH',      # 纳指100
    'N225': '513520.SH',     # 日经225
    'GDAXI': '513030.SH',    # 德国DAX
    'HSI': '159920.SZ',      # 恒生指数
    'HSTECH.HK': '513130.SH',  # 恒生科技
}


def analyze_first_day(nav: pd.DataFrame):
    """2.1 首日 NAV 检查"""
    print_section("2.1 首日 NAV 检查")

    first = nav.iloc[0]
    print(f"  首日日期: {first['date'].date()}")
    print(f"  首日 NAV: {first['nav']:.6f} (预期应为 ~1.0)")
    print(f"  首日收益: {first['daily_return']:.6f}")

    if abs(first['nav'] - 1.0) > 0.001:
        print(f"  [!] 首日 NAV 偏离 1.0 超过 0.1%，存在逻辑瑕疵")
        print(f"      原因: 首日 current_holdings 为空时，仍计算了 open-to-close 收益")
    else:
        print(f"  [OK] 首日 NAV 接近 1.0")

    # 第二天检查
    if len(nav) > 1:
        second = nav.iloc[1]
        print(f"  次日 NAV: {second['nav']:.6f}, 收益: {second['daily_return']:.6f}")

    return {'first_nav': first['nav'], 'first_return': first['daily_return']}


def analyze_t1_execution_bias(days: List[dict], nav: pd.DataFrame):
    """2.2 T+1 执行偏差分析"""
    print_section("2.2 T+1 执行偏差分析")

    # 分析跨市场 ETF 的 index_return vs etf_return_ctc 差异
    print("  跨市场 ETF 信号源(指数) vs 交易源(ETF) 收益差异:")
    diff_by_code = defaultdict(list)

    for day in days:
        holdings = set(day.get('holdings', []))
        for code, asset in day.get('assets', {}).items():
            if code not in CROSS_MARKET_ETFS:
                continue
            idx_ret = asset.get('index_return')
            etf_ret = asset.get('etf_return_ctc')
            if idx_ret is not None and etf_ret is not None:
                diff_by_code[code].append({
                    'date': day['date'],
                    'index_return': idx_ret,
                    'etf_return_ctc': etf_ret,
                    'diff': etf_ret - idx_ret,
                    'is_held': asset.get('is_held', False),
                })

    for code in sorted(diff_by_code.keys()):
        records = diff_by_code[code]
        diffs = [r['diff'] for r in records]
        held_records = [r for r in records if r['is_held']]
        held_diffs = [r['diff'] for r in held_records]
        print(f"\n    {code} ({CROSS_MARKET_ETFS.get(code, '?')}):")
        print(f"      全部天数: {len(records)}, diff 均值={np.mean(diffs):.4%}, std={np.std(diffs):.4%}")
        if held_diffs:
            print(f"      持有天数: {len(held_diffs)}, diff 均值={np.mean(held_diffs):.4%}, std={np.std(held_diffs):.4%}")
        # 极端差异
        large_diffs = [r for r in records if abs(r['diff']) > 0.02]
        if large_diffs:
            print(f"      极端差异(|diff|>2%): {len(large_diffs)} 次")
            for r in large_diffs[:5]:
                print(f"        {r['date']}: 指数={r['index_return']:+.4%}, "
                      f"ETF={r['etf_return_ctc']:+.4%}, diff={r['diff']:+.4%}")

    # 分析极端日
    print_section("2.2a 极端日归因")
    extreme_days = nav[(nav['daily_return'] > 0.05) | (nav['daily_return'] < -0.05)]
    print(f"  极端日(|收益|>5%): {len(extreme_days)} 次")
    for _, row in extreme_days.iterrows():
        date_str = row['date'].strftime('%Y-%m-%d')
        # 找到 detail 中该日的持仓
        day_detail = None
        for d in days:
            if d['date'] == date_str:
                day_detail = d
                break
        if day_detail:
            held_assets = []
            for code, asset in day_detail.get('assets', {}).items():
                if asset.get('is_held'):
                    held_assets.append(
                        f"{code}(etf_ret={asset.get('etf_return_ctc', 0):+.2%})"
                    )
            print(f"    {date_str}: {row['daily_return']:+.4%} | 持仓: {', '.join(held_assets)}")

    return {'extreme_days': len(extreme_days)}


def analyze_premium_impact(days: List[dict]):
    """2.3 溢价率影响分析"""
    print_section("2.3 溢价率影响分析")

    # 收集每个 QDII ETF 的溢价率分布
    premium_by_code = defaultdict(list)
    # 记录高溢价时买入后的收益
    high_premium_entries = []

    for day in days:
        for code, asset in day.get('assets', {}).items():
            premium = asset.get('premium')
            if premium is not None:
                premium_by_code[code].append({
                    'date': day['date'],
                    'premium': premium,
                    'is_held': asset.get('is_held', False),
                    'holding_days': asset.get('holding_days', 0),
                    'cum_return_etf': asset.get('cum_return_etf'),
                })

    print("  各资产溢价率分布:")
    for code in sorted(premium_by_code.keys()):
        records = premium_by_code[code]
        premiums = [r['premium'] for r in records]
        held_records = [r for r in records if r['is_held']]
        held_premiums = [r['premium'] for r in held_records]
        print(f"\n    {code}:")
        print(f"      全部: n={len(premiums)}, 均值={np.mean(premiums):.4%}, "
              f"中位数={np.median(premiums):.4%}, std={np.std(premiums):.4%}")
        if held_premiums:
            print(f"      持有: n={len(held_premiums)}, 均值={np.mean(held_premiums):.4%}, "
                  f"中位数={np.median(held_premiums):.4%}, std={np.std(held_premiums):.4%}")
            # 高溢价时买入（>5%）
            high_prem = [r for r in held_records if r['premium'] > 0.05]
            if high_prem:
                cum_rets = [r['cum_return_etf'] for r in high_prem if r['cum_return_etf'] is not None]
                print(f"      高溢价(>5%)持有: {len(high_prem)} 次")
                if cum_rets:
                    print(f"        平均累计收益: {np.mean(cum_rets):.4%}")
                    print(f"        亏损比例: {sum(1 for r in cum_rets if r < 0)/len(cum_rets)*100:.1f}%")

    # NDX (513100.SH) 专项分析
    ndx_code = 'NDX'
    if ndx_code in premium_by_code:
        print_section("2.3a NDX (513100.SH) 溢价专项分析")
        ndx_records = premium_by_code[ndx_code]
        ndx_held = [r for r in ndx_records if r['is_held']]
        ndx_premiums = [r['premium'] for r in ndx_held]
        if ndx_premiums:
            # 溢价率分桶统计
            buckets = [(0, 0.02), (0.02, 0.05), (0.05, 0.10), (0.10, 1.0)]
            print(f"  NDX 持有期间溢价率分桶:")
            for lo, hi in buckets:
                in_bucket = [r for r in ndx_held if lo <= r['premium'] < hi]
                if not in_bucket:
                    continue
                cum_rets = [r['cum_return_etf'] for r in in_bucket if r['cum_return_etf'] is not None]
                pct = len(in_bucket) / len(ndx_held) * 100
                avg_ret = np.mean(cum_rets) if cum_rets else float('nan')
                print(f"    [{lo:.0%}, {hi:.0%}): {len(in_bucket)} 天 ({pct:.1f}%), "
                      f"平均累计收益={avg_ret:.4%}" if cum_rets else
                      f"    [{lo:.0%}, {hi:.0%}): {len(in_bucket)} 天 ({pct:.1f}%), 无累计收益数据")

    return {}


def main():
    print_section("Task 2: 收益计算问题诊断")

    nav = load_nav()
    signals = load_signals()
    days = load_detail_days()
    meta = load_detail_meta()

    print(f"  数据期间: {meta['start_date']} ~ {meta['end_date']}")

    results = {}

    # 2.1 首日 NAV
    results['first_day'] = analyze_first_day(nav)

    # 2.2 T+1 执行偏差
    results['t1_bias'] = analyze_t1_execution_bias(days, nav)

    # 2.3 溢价率影响
    results['premium'] = analyze_premium_impact(days)

    print_section("Task 2 总结")
    print(f"  1. 首日 NAV = {results['first_day']['first_nav']:.6f}，存在轻微逻辑瑕疵")
    print(f"  2. 极端日共 {results['t1_bias']['extreme_days']} 次，需关注跨市场 ETF 的 open-to-close 偏差")
    print(f"  3. QDII ETF 溢价率问题需要关注，高溢价买入可能侵蚀动量收益")

    return results


if __name__ == '__main__':
    main()
