"""
Task 5: 整体收益归因分析

分析维度：
5.1 收益来源集中度 - 去掉最好/最差 N 天后的收益
5.2 持仓收益 vs 决策收益 - 静态组合 vs 轮动策略对比
5.3 分阶段表现 - 2023 年失效原因分析
"""

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

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, compute_drawdown, compute_sharpe,
    compute_annual_return, yearly_stats,
)


def analyze_return_concentration(nav: pd.DataFrame):
    """5.1 收益来源集中度"""
    print_section("5.1 收益来源集中度")

    returns = nav['daily_return'].values.copy()
    n = len(returns)
    original_nav = (1 + returns).prod()

    print(f"  原始累计净值: {original_nav:.4f} (收益: {original_nav-1:+.2%})")
    print(f"  总交易日: {n}")

    # 去掉最好 N 天
    print(f"\n  去掉最好 N 天后的收益:")
    for n_remove in [5, 10, 20, 50]:
        if n_remove >= n:
            continue
        sorted_returns = np.sort(returns)
        # 去掉最大的 n_remove 个
        trimmed = sorted_returns[:-n_remove] if n_remove > 0 else sorted_returns
        new_nav = (1 + trimmed).prod()
        loss = (original_nav - new_nav) / original_nav * 100
        print(f"    去掉最好 {n_remove} 天: 净值={new_nav:.4f} ({new_nav-1:+.2%}), "
              f"收益损失 {loss:.1f}%")

    # 去掉最差 N 天
    print(f"\n  去掉最差 N 天后的收益:")
    for n_remove in [5, 10, 20, 50]:
        if n_remove >= n:
            continue
        sorted_returns = np.sort(returns)
        # 去掉最小的 n_remove 个
        trimmed = sorted_returns[n_remove:]
        new_nav = (1 + trimmed).prod()
        gain = (new_nav - original_nav) / original_nav * 100
        print(f"    去掉最差 {n_remove} 天: 净值={new_nav:.4f} ({new_nav-1:+.2%}), "
              f"收益增加 {gain:.1f}%")

    # 依赖度指标
    top5_nav = (1 + np.sort(returns)[:-5]).prod()
    dependency = (original_nav - top5_nav) / original_nav * 100
    print(f"\n  收益依赖度: 最好 5 天贡献了 {dependency:.1f}% 的最终净值")
    if dependency > 30:
        print(f"  [!] 收益高度集中在少数大日子，策略对择时依赖严重")
    elif dependency > 15:
        print(f"  [~] 收益中等集中，部分依赖少数大日子")
    else:
        print(f"  [OK] 收益分布较为均匀")

    return {'dependency_pct': dependency}


def analyze_static_vs_rotation(days: List[dict], nav: pd.DataFrame):
    """5.2 持仓收益 vs 决策收益"""
    print_section("5.2 静态组合 vs 轮动策略")

    # 统计各资产被持有天数和持有期间收益
    asset_hold_stats = defaultdict(lambda: {'days': 0, 'returns': []})

    for day in days:
        for code, asset in day.get('assets', {}).items():
            if asset.get('is_held') and asset.get('etf_return_ctc') is not None:
                asset_hold_stats[code]['days'] += 1
                asset_hold_stats[code]['returns'].append(asset['etf_return_ctc'])

    print("  各资产持有统计:")
    total_days = len(days)
    for code in sorted(asset_hold_stats.keys()):
        stats = asset_hold_stats[code]
        rets = stats['returns']
        hold_pct = stats['days'] / total_days * 100
        avg_daily = np.mean(rets) if rets else 0
        cum_ret = (1 + np.array(rets)).prod() - 1 if rets else 0
        print(f"    {code}: 持有 {stats['days']} 天 ({hold_pct:.1f}%), "
              f"日均={avg_daily:.4%}, 持有期累计={cum_ret:+.2%}")

    # 模拟静态组合：始终等权持有 NDX + GC=F + 399006.SZ
    static_codes = ['NDX', 'GC=F', '399006.SZ']
    print(f"\n  模拟静态组合 (始终等权持有 {', '.join(static_codes)}):")

    static_returns = []
    for day in days:
        day_ret = 0.0
        count = 0
        for code in static_codes:
            asset = day.get('assets', {}).get(code, {})
            etf_ret = asset.get('etf_return_ctc')
            if etf_ret is not None:
                day_ret += etf_ret / len(static_codes)
                count += 1
        if count > 0:
            static_returns.append(day_ret)
        else:
            static_returns.append(0.0)

    static_nav = pd.Series(static_returns).add(1).cumprod()
    static_total = static_nav.iloc[-1] - 1
    static_dd = compute_drawdown(static_nav).min()
    static_sharpe = compute_sharpe(pd.Series(static_returns))

    # 轮动策略
    rot_nav = nav['nav']
    rot_total = rot_nav.iloc[-1] / rot_nav.iloc[0] - 1
    rot_dd = compute_drawdown(rot_nav).min()
    rot_sharpe = compute_sharpe(nav['daily_return'])

    print(f"    静态组合: 累计={static_total:+.2%}, 回撤={static_dd:.2%}, 夏普={static_sharpe:.2f}")
    print(f"    轮动策略: 累计={rot_total:+.2%}, 回撤={rot_dd:.2%}, 夏普={rot_sharpe:.2f}")
    print(f"    轮动超额: {rot_total - static_total:+.2%}")

    # 其他静态组合对比
    print(f"\n  其他静态组合对比:")
    test_combos = [
        ('NDX', 'GC=F', 'H30269.CSI'),
        ('NDX', 'N225', '399006.SZ'),
        ('NDX', 'GC=F', 'GDAXI'),
    ]
    for combo in test_combos:
        combo_rets = []
        for day in days:
            day_ret = 0.0
            count = 0
            for code in combo:
                asset = day.get('assets', {}).get(code, {})
                etf_ret = asset.get('etf_return_ctc')
                if etf_ret is not None:
                    day_ret += etf_ret / len(combo)
                    count += 1
            if count > 0:
                combo_rets.append(day_ret)
            else:
                combo_rets.append(0.0)

        c_nav = pd.Series(combo_rets).add(1).cumprod()
        c_total = c_nav.iloc[-1] - 1
        c_dd = compute_drawdown(c_nav).min()
        c_sharpe = compute_sharpe(pd.Series(combo_rets))
        print(f"    {combo}: 累计={c_total:+.2%}, 回撤={c_dd:.2%}, 夏普={c_sharpe:.2f}")

    return {}


def analyze_2023_failure(days: List[dict], nav: pd.DataFrame, signals: pd.DataFrame):
    """5.3 2023 年失效原因分析"""
    print_section("5.3 分阶段表现 & 2023 年失效分析")

    # 分年度统计
    yearly = yearly_stats(nav)
    print("  分年度表现:")
    for _, row in yearly.iterrows():
        marker = " <-- 失效年份" if abs(row['total_return']) < 0.02 else ""
        print(f"    {int(row['year'])}: 累计={row['total_return']:+.2%}, "
              f"回撤={row['max_drawdown']:.2%}, 夏普={row['sharpe']:.2f}{marker}")

    # 2023 年详细分析
    print(f"\n  2023 年详细分析:")
    nav_2023 = nav[nav['date'].dt.year == 2023].copy()
    if len(nav_2023) == 0:
        print("    无 2023 年数据")
        return {}

    print(f"    2023 年交易日: {len(nav_2023)}")
    print(f"    2023 年累计收益: {nav_2023['nav'].iloc[-1]/nav_2023['nav'].iloc[0]-1:+.2%}")
    print(f"    2023 年最大回撤: {compute_drawdown(nav_2023['nav']).min():.2%}")

    # 2023 年持仓分布
    signals_2023 = signals[signals['date'].dt.year == 2023].copy()
    holding_days = defaultdict(int)
    for _, row in signals_2023.iterrows():
        holdings = ast.literal_eval(row['holdings']) if isinstance(row['holdings'], str) else row['holdings']
        for code in holdings:
            holding_days[code] += 1

    print(f"\n    2023 年持仓分布:")
    total_days_2023 = len(signals_2023)
    for code, count in sorted(holding_days.items(), key=lambda x: -x[1]):
        print(f"      {code}: {count} 天 ({count/total_days_2023*100:.1f}%)")

    # 2023 年调仓次数
    rebal_2023 = signals_2023['is_rebalance'].sum()
    print(f"\n    2023 年调仓次数: {rebal_2023}")

    # 2023 年月度收益
    nav_2023_copy = nav_2023.copy()
    nav_2023_copy['month'] = nav_2023_copy['date'].dt.month
    print(f"\n    2023 年月度收益:")
    for month, grp in nav_2023_copy.groupby('month'):
        m_ret = grp['nav'].iloc[-1] / grp['nav'].iloc[0] - 1
        print(f"      {month}月: {m_ret:+.2%}")

    # 2023 年动量得分分布
    days_2023 = [d for d in days if d['date'].startswith('2023')]
    momentum_2023 = defaultdict(list)
    for day in days_2023:
        for code, asset in day.get('assets', {}).items():
            m = asset.get('momentum')
            if m is not None:
                momentum_2023[code].append(m)

    print(f"\n    2023 年动量得分分布:")
    for code in sorted(momentum_2023.keys()):
        vals = momentum_2023[code]
        if vals:
            arr = np.array(vals)
            print(f"      {code}: 均值={arr.mean():.4f}, std={arr.std():.4f}, "
                  f"正动量占比={sum(1 for v in vals if v > 0)/len(vals)*100:.1f}%")

    return {}


def main():
    print_section("Task 5: 整体收益归因分析")

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

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

    results = {}

    # 5.1 收益集中度
    results['concentration'] = analyze_return_concentration(nav)

    # 5.2 静态 vs 轮动
    results['static_vs_rotation'] = analyze_static_vs_rotation(days, nav)

    # 5.3 2023 年失效
    results['year_2023'] = analyze_2023_failure(days, nav, signals)

    print_section("Task 5 总结")
    dep = results['concentration']['dependency_pct']
    print(f"  1. 收益依赖度: 最好 5 天贡献了 {dep:.1f}% 的最终净值")
    print(f"  2. 轮动策略 vs 静态组合的超额收益体现了决策价值")
    print(f"  3. 2023 年动量因子可能因全球加息环境而失效")

    return results


if __name__ == '__main__':
    main()
