"""
04_merge_panel.py
面板数据合并模块：将 WDI + WGI + 参照数据源合并为统一的国家-年份面板
Panel Merge Module: combine WDI + WGI + reference sources into one panel

用途 / Purpose:
    将 01/02/03 三个采集模块产出的独立数据源，按 (iso3, year) 键合并为
    单一的 OECD-38 面板数据框（38 国 × 24 年 = 912 行），作为后续预处理
    与 RE 指数构建的输入。

依赖 / Dependencies: pandas, numpy
"""

import logging
from itertools import product
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("04_merge_panel")

DATA_DIR = Path("./data")

OECD38 = [
    "AUS", "AUT", "BEL", "CAN", "CHE", "CHL", "COL", "CRI", "CZE", "DEU",
    "DNK", "ESP", "EST", "FIN", "FRA", "GBR", "GRC", "HUN", "IRL", "ISL",
    "ISR", "ITA", "JPN", "KOR", "LTU", "LUX", "LVA", "MEX", "NLD", "NOR",
    "NZL", "POL", "PRT", "SVK", "SVN", "SWE", "TUR", "USA",
]
YEARS = list(range(2000, 2024))


def build_skeleton() -> pd.DataFrame:
    """Build the full (iso3 x year) skeleton — 38 x 24 = 912 rows."""
    rows = list(product(OECD38, YEARS))
    skeleton = pd.DataFrame(rows, columns=["iso3", "year"])
    assert len(skeleton) == 38 * 24 == 912, "Skeleton must have exactly 912 rows"
    return skeleton


def safe_read_csv(path: Path) -> pd.DataFrame:
    if not path.exists():
        log.warning("Missing input file %s; continuing with empty frame.", path)
        return pd.DataFrame()
    return pd.read_csv(path)


def main():
    skeleton = build_skeleton()

    wdi = safe_read_csv(DATA_DIR / "wb_wdi_raw.csv")
    wgi = safe_read_csv(DATA_DIR / "wgi_raw.csv")
    ref = safe_read_csv(DATA_DIR / "reference_comparison_variables.csv")

    panel = skeleton.copy()
    for name, df in [("wdi", wdi), ("wgi", wgi), ("ref", ref)]:
        if df.empty:
            continue
        if "indicator_name" in df.columns and "value" in df.columns:
            wide = df.pivot_table(
                index=["iso3", "year"], columns="indicator_name", values="value"
            ).reset_index()
            panel = panel.merge(wide, on=["iso3", "year"], how="left")
        else:
            panel = panel.merge(df, on=["iso3", "year"], how="left")
        log.info("Merged %s: %d columns now in panel", name, panel.shape[1])

    panel.to_csv(DATA_DIR / "panel_merged_raw.csv", index=False)
    log.info(
        "Merged panel complete: %d rows x %d columns -> data/panel_merged_raw.csv",
        panel.shape[0], panel.shape[1],
    )

    # Basic coverage report per column
    coverage = (
        panel.drop(columns=["iso3", "year"])
        .notna()
        .mean()
        .sort_values(ascending=False)
        .round(4)
    )
    coverage.to_csv(DATA_DIR / "column_coverage_report.csv", header=["coverage_rate"])
    log.info("Coverage report written -> data/column_coverage_report.csv")


if __name__ == "__main__":
    main()
