"""
预测值覆盖率效果分析

对比有/无预测值样本的业务指标差异
主要关注: str_plus, ros_minus, rovn, vovh24
"""

import pandas as pd
import glob
import os

# 数据目录
DATA_DIR = "tasks/承接/线上实验/output/07_预测值覆盖率分析"

# 核心业务指标
METRICS = ['str_plus', 'ros_minus', 'rovn', 'vovh24']

# 辅助指标
AUX_METRICS = ['sample_cnt', 'sample_ratio', 'str_one', 'ros_one', 'str', 'ros', 'dau', 'exp']


def load_all_data():
    """加载所有天的数据"""
    files = sorted(glob.glob(os.path.join(DATA_DIR, "*.csv")))
    if not files:
        print(f"未找到数据文件: {DATA_DIR}")
        return None

    dfs = []
    for f in files:
        df = pd.read_csv(f)
        dfs.append(df)
        print(f"加载: {os.path.basename(f)} ({len(df)} 行)")

    return pd.concat(dfs, ignore_index=True)


def filter_app4(df):
    """只保留 apptype=4 的数据（实验平台）"""
    return df[df['apptype'] == 4].copy()


def calc_lift(exp_val, ctrl_val):
    """计算提升幅度"""
    if ctrl_val == 0:
        return float('inf') if exp_val > 0 else 0
    return (exp_val - ctrl_val) / ctrl_val * 100


def analyze_by_has_pred(df):
    """按 有/无预测值 对比各组的业务指标"""
    print("\n" + "=" * 80)
    print("【有/无预测值 业务指标对比】")
    print("=" * 80)

    # 筛选 apptype=4
    df4 = filter_app4(df)

    # 按 abcode + has_pred 汇总（多天平均）
    agg_cols = {m: 'mean' for m in METRICS + AUX_METRICS if m in df4.columns}
    agg_cols['sample_cnt'] = 'sum'  # 样本量用求和

    summary = df4.groupby(['abcode', 'has_pred']).agg(agg_cols).round(6)

    print("\n各组指标均值（多天汇总）:")
    print(summary[METRICS].to_string())

    return summary


def compare_vs_baseline(df):
    """对比实验组 vs 对照组"""
    print("\n" + "=" * 80)
    print("【实验组 vs 对照组 业务指标对比】")
    print("=" * 80)

    df4 = filter_app4(df)

    results = []

    for has_pred in ['有预测值', '无预测值']:
        print(f"\n--- {has_pred} ---")

        sub = df4[df4['has_pred'] == has_pred]

        # 计算各组均值
        group_means = sub.groupby('abcode')[METRICS].mean()

        if '对照组' not in group_means.index:
            print("  [缺少对照组数据]")
            continue

        baseline = group_means.loc['对照组']

        print(f"\n对照组基线: {baseline.to_dict()}")
        print(f"\n各实验组 vs 对照组 提升幅度 (%):")

        for abcode in group_means.index:
            if abcode == '对照组':
                continue

            exp_vals = group_means.loc[abcode]
            lifts = {m: calc_lift(exp_vals[m], baseline[m]) for m in METRICS}

            print(f"\n  {abcode}:")
            for m in METRICS:
                sign = '+' if lifts[m] > 0 else ''
                print(f"    {m}: {exp_vals[m]:.6f} ({sign}{lifts[m]:.2f}%)")

            results.append({
                'has_pred': has_pred,
                'abcode': abcode,
                **{f'{m}_val': exp_vals[m] for m in METRICS},
                **{f'{m}_lift': lifts[m] for m in METRICS}
            })

    return pd.DataFrame(results)


def compare_pred_vs_nopred(df):
    """对比同一组内 有预测值 vs 无预测值"""
    print("\n" + "=" * 80)
    print("【同组内 有预测值 vs 无预测值 对比】")
    print("=" * 80)

    df4 = filter_app4(df)

    results = []

    for abcode in df4['abcode'].unique():
        sub = df4[df4['abcode'] == abcode]

        has_pred = sub[sub['has_pred'] == '有预测值'][METRICS].mean()
        no_pred = sub[sub['has_pred'] == '无预测值'][METRICS].mean()

        print(f"\n{abcode}:")
        print(f"  有预测值: {has_pred.to_dict()}")
        print(f"  无预测值: {no_pred.to_dict()}")

        diffs = {}
        for m in METRICS:
            diff = calc_lift(has_pred[m], no_pred[m])
            sign = '+' if diff > 0 else ''
            print(f"  {m} 提升: {sign}{diff:.2f}%")
            diffs[m] = diff

        results.append({
            'abcode': abcode,
            **{f'{m}_有预测值': has_pred[m] for m in METRICS},
            **{f'{m}_无预测值': no_pred[m] for m in METRICS},
            **{f'{m}_lift': diffs[m] for m in METRICS}
        })

    return pd.DataFrame(results)


def daily_trend(df):
    """按天查看指标趋势"""
    print("\n" + "=" * 80)
    print("【日趋势 - 有预测值样本】")
    print("=" * 80)

    df4 = filter_app4(df)
    has_pred = df4[df4['has_pred'] == '有预测值']

    pivot = has_pred.pivot_table(
        index='dt',
        columns='abcode',
        values='rovn',
        aggfunc='mean'
    ).round(6)

    print("\nrovn 日趋势:")
    print(pivot.to_string())

    return pivot


def coverage_stability(df):
    """检查预测覆盖率的稳定性"""
    print("\n" + "=" * 80)
    print("【预测覆盖率稳定性】")
    print("=" * 80)

    df4 = filter_app4(df)

    coverage = df4[df4['has_pred'] == '有预测值'].pivot_table(
        index='dt',
        columns='abcode',
        values='sample_ratio',
        aggfunc='mean'
    ).round(4)

    print("\n各组有预测值样本占比 (按天):")
    print(coverage.to_string())

    print("\n各组覆盖率统计:")
    print(coverage.describe().round(4).to_string())

    return coverage


def daily_lift_stability(df):
    """按天计算实验组 vs 对照组的提升幅度，检查稳定性"""
    print("\n" + "=" * 80)
    print("【多天稳定性分析 - 实验组 vs 对照组 提升幅度】")
    print("=" * 80)

    df4 = filter_app4(df)
    has_pred = df4[df4['has_pred'] == '有预测值']

    results = []
    for dt in sorted(has_pred['dt'].unique()):
        day_data = has_pred[has_pred['dt'] == dt]

        if '对照组' not in day_data['abcode'].values:
            continue

        baseline = day_data[day_data['abcode'] == '对照组'][METRICS].iloc[0]

        for abcode in day_data['abcode'].unique():
            if abcode == '对照组':
                continue
            exp_vals = day_data[day_data['abcode'] == abcode][METRICS].iloc[0]
            lifts = {m: calc_lift(exp_vals[m], baseline[m]) for m in METRICS}
            results.append({
                'dt': dt,
                'abcode': abcode,
                **{f'{m}_lift': lifts[m] for m in METRICS}
            })

    lift_df = pd.DataFrame(results)

    for abcode in lift_df['abcode'].unique():
        print(f"\n{abcode}:")
        sub = lift_df[lift_df['abcode'] == abcode]

        for m in METRICS:
            col = f'{m}_lift'
            values = sub[col].values
            mean_lift = values.mean()
            std_lift = values.std()
            min_lift = values.min()
            max_lift = values.max()

            # 判断稳定性
            is_stable = std_lift < abs(mean_lift) * 0.5 if mean_lift != 0 else std_lift < 1
            stability = "✓稳定" if is_stable else "⚠波动"

            print(f"  {m}: 均值{mean_lift:+.2f}%, 标准差{std_lift:.2f}%, 范围[{min_lift:+.2f}%, {max_lift:+.2f}%] {stability}")

        # 显示每日明细
        print(f"  日明细:")
        for _, row in sub.iterrows():
            lifts_str = " | ".join([f"{m}:{row[f'{m}_lift']:+.2f}%" for m in METRICS])
            print(f"    {row['dt']}: {lifts_str}")

    return lift_df


def compare_pred_effect_by_day(df):
    """按天对比有/无预测值的效果差异"""
    print("\n" + "=" * 80)
    print("【有/无预测值效果差异分析】")
    print("=" * 80)

    df4 = filter_app4(df)

    # 只看对照组，排除策略干扰
    ctrl = df4[df4['abcode'] == '对照组']

    print("\n对照组 - 有/无预测值对比 (排除策略干扰):")

    results = []
    for dt in sorted(ctrl['dt'].unique()):
        day_data = ctrl[ctrl['dt'] == dt]
        has_pred = day_data[day_data['has_pred'] == '有预测值'][METRICS + ['sample_cnt']].iloc[0]
        no_pred = day_data[day_data['has_pred'] == '无预测值'][METRICS + ['sample_cnt']].iloc[0]

        diffs = {m: calc_lift(has_pred[m], no_pred[m]) for m in METRICS}
        results.append({
            'dt': dt,
            'sample_有预测值': has_pred['sample_cnt'],
            'sample_无预测值': no_pred['sample_cnt'],
            **{f'{m}_有': has_pred[m] for m in METRICS},
            **{f'{m}_无': no_pred[m] for m in METRICS},
            **{f'{m}_diff': diffs[m] for m in METRICS}
        })

    diff_df = pd.DataFrame(results)

    # 汇总统计
    print("\n指标差异汇总 (有预测值 vs 无预测值):")
    for m in METRICS:
        col = f'{m}_diff'
        mean_diff = diff_df[col].mean()
        std_diff = diff_df[col].std()
        print(f"  {m}: 均值差异 {mean_diff:+.1f}%, 标准差 {std_diff:.1f}%")

    print("\n日明细:")
    for _, row in diff_df.iterrows():
        print(f"  {row['dt']}:")
        print(f"    样本量: 有预测值 {row['sample_有预测值']:,.0f} | 无预测值 {row['sample_无预测值']:,.0f}")
        for m in METRICS:
            print(f"    {m}: {row[f'{m}_有']:.6f} vs {row[f'{m}_无']:.6f} ({row[f'{m}_diff']:+.1f}%)")

    return diff_df


def daily_metrics_by_pred(df):
    """按天、分组、有无预测值 输出指标明细"""
    print("\n" + "=" * 80)
    print("【分天指标明细 - 有/无预测值】")
    print("=" * 80)

    df4 = filter_app4(df)

    # 选择需要的列
    cols = ['dt', 'abcode', 'has_pred', 'sample_cnt', 'sample_ratio'] + METRICS

    result = df4[cols].sort_values(['dt', 'abcode', 'has_pred'], ascending=[True, True, False])

    # 输出到文件
    output_file = os.path.join(DATA_DIR, "分天指标_有无预测值.csv")
    result.to_csv(output_file, index=False, encoding='utf-8-sig')
    print(f"\n输出文件: {output_file}")

    # 打印预览
    print("\n数据预览:")
    print(result.to_string(index=False))

    return result


def daily_lift_to_file(df):
    """按天计算实验组 vs 对照组提升幅度，输出到文件"""
    print("\n" + "=" * 80)
    print("【分天提升幅度 - 实验组 vs 对照组】")
    print("=" * 80)

    df4 = filter_app4(df)

    results = []
    # 有预测值、无预测值、整体
    for has_pred in ['有预测值', '无预测值', '整体']:
        if has_pred == '整体':
            # 整体：按 dt + abcode 汇总（加权平均）
            sub = df4.groupby(['dt', 'abcode']).apply(
                lambda g: pd.Series({
                    'sample_cnt': g['sample_cnt'].sum(),
                    **{m: (g[m] * g['sample_cnt']).sum() / g['sample_cnt'].sum() for m in METRICS}
                })
            ).reset_index()
        else:
            sub = df4[df4['has_pred'] == has_pred]

        for dt in sorted(sub['dt'].unique()):
            day_data = sub[sub['dt'] == dt]

            if '对照组' not in day_data['abcode'].values:
                continue

            baseline = day_data[day_data['abcode'] == '对照组'][METRICS].iloc[0]

            for abcode in day_data['abcode'].unique():
                exp_vals = day_data[day_data['abcode'] == abcode][METRICS].iloc[0]
                sample_cnt = day_data[day_data['abcode'] == abcode]['sample_cnt'].iloc[0]
                if abcode == '对照组':
                    lifts = {m: 0 for m in METRICS}
                else:
                    lifts = {m: calc_lift(exp_vals[m], baseline[m]) for m in METRICS}

                results.append({
                    'dt': dt,
                    'has_pred': has_pred,
                    'abcode': abcode,
                    'sample_cnt': int(sample_cnt),
                    **{m: exp_vals[m] for m in METRICS},
                    **{f'{m}_lift': round(lifts[m], 2) for m in METRICS}
                })

    lift_df = pd.DataFrame(results)
    # 排序：整体在最后
    order = {'有预测值': 0, '无预测值': 1, '整体': 2}
    lift_df['_order'] = lift_df['has_pred'].map(order)
    lift_df = lift_df.sort_values(['dt', '_order', 'abcode'], ascending=[True, True, True])
    lift_df = lift_df.drop('_order', axis=1)

    # 输出到文件
    output_file = os.path.join(DATA_DIR, "分天提升幅度.csv")
    lift_df.to_csv(output_file, index=False, encoding='utf-8-sig')
    print(f"\n输出文件: {output_file}")

    # 打印预览
    print("\n数据预览:")
    print(lift_df.to_string(index=False))

    return lift_df


def overall_lift_summary(df):
    """整体效果汇总（不分有无预测值）"""
    print("\n" + "=" * 80)
    print("【整体效果汇总 - 不分有无预测值】")
    print("=" * 80)

    df4 = filter_app4(df)

    # 按 dt + abcode 汇总（加权平均）
    overall = df4.groupby(['dt', 'abcode']).apply(
        lambda g: pd.Series({
            'sample_cnt': g['sample_cnt'].sum(),
            **{m: (g[m] * g['sample_cnt']).sum() / g['sample_cnt'].sum() for m in METRICS}
        })
    ).reset_index()

    results = []
    for dt in sorted(overall['dt'].unique()):
        day_data = overall[overall['dt'] == dt]

        if '对照组' not in day_data['abcode'].values:
            continue

        baseline = day_data[day_data['abcode'] == '对照组'][METRICS].iloc[0]

        for abcode in day_data['abcode'].unique():
            if abcode == '对照组':
                continue
            exp_vals = day_data[day_data['abcode'] == abcode][METRICS].iloc[0]
            lifts = {m: calc_lift(exp_vals[m], baseline[m]) for m in METRICS}
            results.append({
                'dt': dt,
                'abcode': abcode,
                **{f'{m}_lift': lifts[m] for m in METRICS}
            })

    lift_df = pd.DataFrame(results)

    print("\n各实验组整体效果（多天汇总）:")
    for abcode in lift_df['abcode'].unique():
        sub = lift_df[lift_df['abcode'] == abcode]
        print(f"\n{abcode}:")
        for m in METRICS:
            col = f'{m}_lift'
            mean_lift = sub[col].mean()
            std_lift = sub[col].std()
            is_stable = std_lift < abs(mean_lift) * 0.5 if mean_lift != 0 else std_lift < 1
            stability = "✓稳定" if is_stable else "⚠波动"
            print(f"  {m}: 均值{mean_lift:+.2f}%, 标准差{std_lift:.2f}% {stability}")

        # 日明细
        print(f"  日明细:")
        for _, row in sub.iterrows():
            lifts_str = " | ".join([f"{m}:{row[f'{m}_lift']:+.2f}%" for m in METRICS])
            print(f"    {row['dt']}: {lifts_str}")

    return lift_df


def main():
    print("=" * 80)
    print("预测值覆盖率效果分析")
    print("=" * 80)

    # 加载数据
    df = load_all_data()
    if df is None:
        return

    print(f"\n总数据量: {len(df)} 行")
    print(f"日期范围: {df['dt'].min()} ~ {df['dt'].max()}")
    print(f"包含天数: {df['dt'].nunique()} 天")

    # 1. 分天指标明细
    daily_metrics_by_pred(df)

    # 2. 分天提升幅度（有预测值、无预测值、整体）
    daily_lift_to_file(df)

    # 3. 整体效果汇总
    overall_lift_summary(df)

    # 4. 有预测值样本稳定性
    print("\n" + "=" * 80)
    print("【有预测值样本 - 多天稳定性】")
    print("=" * 80)
    daily_lift_stability(df)

    print("\n" + "=" * 80)
    print("分析完成")
    print("=" * 80)


if __name__ == "__main__":
    main()
