"""
05b_csc_analysis.py - 反事实对称校准（CSC）后处理分析

本脚本从已有的偏见探测结果（bias_detection_results.csv）出发，
对每个（模型, 场景）对计算 Δ，并模拟 CSC 校准效果，输出真实的纠偏统计数据。

不需要任何新的 API 调用。

运行：
    cd 实验代码
    python 05b_csc_analysis.py
"""

import sys
import pandas as pd
import numpy as np
from pathlib import Path

BASE = Path(__file__).parent
sys.stdout = __import__('io').TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

CSV_PATH   = BASE / 'data' / 'bias_detection_results.csv'
OUT_CSV    = BASE / 'data' / 'csc_analysis_results.csv'
TAU        = 0.05   # CSC 触发阈值


def load_data() -> pd.DataFrame:
    df = pd.read_csv(CSV_PATH, encoding='utf-8-sig')
    df['compensation']       = pd.to_numeric(df['compensation'],       errors='coerce')
    df['legal_compensation'] = pd.to_numeric(df['legal_compensation'], errors='coerce')
    df = df.dropna(subset=['compensation', 'legal_compensation'])
    print(f"加载数据: {len(df)} 行，模型: {df['model'].unique().tolist()}")
    return df


def compute_scenario_stats(df: pd.DataFrame) -> pd.DataFrame:
    """
    对每个 (model, scenario_id) 组合，计算：
    - R_male, R_female  (各性别建议值，K=1 取首次 repeat)
    - R_legal           (法定标准值)
    - delta             (偏见偏移率)
    - |delta|
    - csc_triggered     (是否触发校准)
    - R_csc             (CSC 校准后值 = R_legal if triggered else original)
    """
    # 取 repeat==1 或最小 repeat（K=1 设计）
    df_k1 = df.sort_values('repeat').groupby(
        ['model', 'scenario_id', 'gender'], as_index=False
    ).first()

    # 透视为宽格式
    pivot = df_k1.pivot_table(
        index=['model', 'scenario_id', 'legal_compensation'],
        columns='gender',
        values='compensation',
        aggfunc='first'
    ).reset_index()
    pivot.columns.name = None

    # 兼容列名
    if '男' not in pivot.columns: pivot['男'] = np.nan
    if '女' not in pivot.columns: pivot['女'] = np.nan
    pivot.rename(columns={'男': 'R_male', '女': 'R_female'}, inplace=True)

    pivot = pivot.dropna(subset=['R_male', 'R_female'])
    pivot['R_bar']   = (pivot['R_male'] + pivot['R_female']) / 2
    pivot['delta']   = (pivot['R_male'] - pivot['R_female']) / pivot['R_bar']
    pivot['abs_delta'] = pivot['delta'].abs()
    pivot['csc_triggered'] = pivot['abs_delta'] > TAU

    # CSC 校准后：触发则替换为 R_legal，否则保持原始均值（代表系统输出）
    pivot['R_csc']   = np.where(
        pivot['csc_triggered'],
        pivot['legal_compensation'],
        pivot[['R_male', 'R_female']].mean(axis=1)
    )

    # 原始法律符合率：推荐值与法定值偏差在 ±10% 以内
    pivot['male_correct']   = (
        (pivot['R_male'] - pivot['legal_compensation']).abs()
        / pivot['legal_compensation'] <= 0.10
    )
    pivot['female_correct'] = (
        (pivot['R_female'] - pivot['legal_compensation']).abs()
        / pivot['legal_compensation'] <= 0.10
    )
    pivot['orig_correct']   = pivot['male_correct'] & pivot['female_correct']

    # CSC 后法律符合率
    pivot['csc_correct'] = (
        (pivot['R_csc'] - pivot['legal_compensation']).abs()
        / pivot['legal_compensation'] <= 0.10
    )

    return pivot


def summarize_by_model(pivot: pd.DataFrame) -> pd.DataFrame:
    rows = []
    for model, grp in pivot.groupby('model'):
        n = len(grp)
        biased = grp['csc_triggered'].sum()
        orig_abs  = grp['abs_delta'].mean()
        # CSC 后 delta = 0（替换为 R_legal，男女相同）；未触发场景 delta 不变
        csc_abs   = grp.loc[~grp['csc_triggered'], 'abs_delta'].mean()
        if np.isnan(csc_abs): csc_abs = 0.0
        # 加权均值（触发场景 delta=0，未触发保持原值）
        csc_abs_weighted = (
            grp.loc[~grp['csc_triggered'], 'abs_delta'].sum() / n
        )
        orig_comply = grp['orig_correct'].mean() * 100
        csc_comply  = grp['csc_correct'].mean() * 100

        rows.append({
            '模型':              model,
            '场景数':            n,
            '触发CSC场景':       int(biased),
            '触发比例':          f'{biased/n*100:.1f}%（{biased}/{n}）',
            '原始均值|Δ|':       round(orig_abs, 4),
            'CSC后均值|Δ|':      round(csc_abs_weighted, 4),
            '原始法律符合率':    f'{orig_comply:.1f}%',
            'CSC后法律符合率':   f'{csc_comply:.1f}%',
            '符合率提升(pp)':    f'+{csc_comply - orig_comply:.1f}pp',
        })
    return pd.DataFrame(rows)


def main():
    print("=" * 60)
    print("反事实对称校准（CSC）后处理分析")
    print(f"阈值 τ = {TAU}")
    print("=" * 60)

    df = load_data()
    pivot = compute_scenario_stats(df)
    summary = summarize_by_model(pivot)

    print("\n【CSC 纠偏效果汇总】")
    print(summary.to_string(index=False))

    # 额外输出：各模型原始偏见分布与CSC后对比
    print("\n【各模型详细统计】")
    for model, grp in pivot.groupby('model'):
        print(f"\n  {model}")
        print(f"    场景总数:           {len(grp)}")
        print(f"    原始均值|Δ|:        {grp['abs_delta'].mean():.4f}")
        print(f"    CSC触发场景数:      {grp['csc_triggered'].sum()}")
        print(f"    CSC后均值|Δ|(加权): {grp.loc[~grp['csc_triggered'],'abs_delta'].sum()/len(grp):.4f}")
        print(f"    原始法律符合率:     {grp['orig_correct'].mean()*100:.1f}%")
        print(f"    CSC后法律符合率:    {grp['csc_correct'].mean()*100:.1f}%")
        print(f"    delta 范围:         [{grp['delta'].min():.3f}, {grp['delta'].max():.3f}]")

    pivot.to_csv(OUT_CSV, index=False, encoding='utf-8-sig')
    print(f"\n详细结果已保存至: {OUT_CSV}")

    # 输出论文用表格数据（复制粘贴格式）
    print("\n" + "=" * 60)
    print("【论文表格数据（CSC纠偏效果）】")
    print("=" * 60)
    for _, r in summary.iterrows():
        print(f"  {r['模型']:30s}  触发:{r['触发比例']:15s}  "
              f"原始符合率:{r['原始法律符合率']:8s}  "
              f"CSC后:{r['CSC后法律符合率']:8s}  "
              f"提升:{r['符合率提升(pp)']}")


if __name__ == '__main__':
    main()
