"""
11_bootstrap_uncertainty.py
Bootstrap 不确定性量化模块：500 次 Dirichlet 权重扰动
Bootstrap Uncertainty Quantification Module: 500-iteration Dirichlet weight perturbation

用途 / Purpose:
    权重方案（07 号脚本的经验/规范融合权重）本身存在不确定性。本模块以
    Dirichlet 分布对每个维度的权重向量做 500 次随机扰动（集中度参数
    concentration=50，扰动幅度适度），每次重新计算 RE 分数，最终报告
    每个国家-年份观测的 RE 分数 2.5% / 50% / 97.5% 分位数，作为置信区间。

依赖 / Dependencies: pandas, numpy
随机种子 / Random seed: 42
"""

import json
import logging
from pathlib import Path

import numpy as np
import pandas as pd

logging.basicConfig(level=logging.INFO, format="%(asctime)s  %(message)s")
log = logging.getLogger("11_bootstrap")

DATA_DIR = Path("./data")
RANDOM_SEED = 42
N_BOOTSTRAP = 500
CONCENTRATION = 50.0


def dirichlet_perturb(weights: dict, rng: np.random.Generator, concentration: float = CONCENTRATION) -> dict:
    cols = list(weights.keys())
    base = np.array([weights[c] for c in cols])
    alpha = base * concentration + 1e-6
    perturbed = rng.dirichlet(alpha)
    return dict(zip(cols, perturbed))


def weighted_score(df: pd.DataFrame, weights: dict) -> pd.Series:
    cols = list(weights.keys())
    w = np.array([weights[c] for c in cols])
    return pd.Series(df[cols].to_numpy(dtype=float).dot(w), index=df.index)


def main():
    panel = pd.read_csv(DATA_DIR / "panel_normalized_minmax.csv")
    with open(DATA_DIR / "dimension_weights.json", "r", encoding="utf-8") as f:
        weight_spec = json.load(f)
    weights = weight_spec["weights"]

    rng = np.random.default_rng(RANDOM_SEED)
    n_obs = len(panel)
    re_samples = np.zeros((N_BOOTSTRAP, n_obs))

    for b in range(N_BOOTSTRAP):
        v_w = dirichlet_perturb(weights["V"], rng)
        c_w = dirichlet_perturb(weights["C"], rng)
        f_w = dirichlet_perturb(weights["F"], rng)

        v = weighted_score(panel, v_w)
        c = weighted_score(panel, c_w)
        f = weighted_score(panel, f_w)
        re_raw = (v * c) / (1 + f)
        re_scaled = 100 * (re_raw - re_raw.min()) / (re_raw.max() - re_raw.min())
        re_samples[b, :] = re_scaled.to_numpy()

        if (b + 1) % 100 == 0:
            log.info("Bootstrap iteration %d / %d complete", b + 1, N_BOOTSTRAP)

    result = panel[["iso3", "year"]].copy()
    result["re_score_mean"] = re_samples.mean(axis=0).round(2)
    result["re_score_ci_low"] = np.percentile(re_samples, 2.5, axis=0).round(2)
    result["re_score_ci_high"] = np.percentile(re_samples, 97.5, axis=0).round(2)
    result["ci_width"] = (result["re_score_ci_high"] - result["re_score_ci_low"]).round(2)

    result.to_csv(DATA_DIR / "re_score_bootstrap_ci.csv", index=False)
    log.info(
        "Bootstrap UQ complete (N=%d, concentration=%.0f) -> data/re_score_bootstrap_ci.csv "
        "(mean CI width=%.2f)",
        N_BOOTSTRAP, CONCENTRATION, result["ci_width"].mean(),
    )


if __name__ == "__main__":
    main()
