#!/usr/bin/env python3
"""把逐条核对过的原始数据记录（data_provenance.json）拼成分析用的面板 panel.csv。

一条记录 = 一个城市 + 一个年份 + 一个字段 + 一个数值 + 它出自哪个文件的哪句话。
这里不做任何推算：没有的就是没有，缺格留空，由分析脚本按预注册规则整行剔除。
"""
from __future__ import annotations

import csv
import json
from pathlib import Path

CODE = Path(__file__).resolve().parent
WORK = CODE.parent

FIELDS = ["water_good_pct", "tourism_visitors", "tourism_revenue",
          "resident_pop", "secondary_gdp"]
CITIES = ["青岛", "烟台", "威海", "潍坊", "日照", "东营", "滨州"]
YEARS = [2021, 2022, 2023]


def main() -> int:
    prov = json.loads((WORK / "data" / "data_provenance.json").read_text(encoding="utf-8"))
    table = {}
    for rec in prov["records"]:
        key = (rec["city"], int(rec["year"]))
        table.setdefault(key, {})
        if rec["field"] in table[key]:
            raise SystemExit(f"同一格出现两条记录，先人工裁决：{key} {rec['field']}")
        table[key][rec["field"]] = rec["value"]
    # 全量面板（预注册里的敏感性分析口径）：所有查到的数都进去，口径差异另行标注
    def write(path, tbl):
        with path.open("w", newline="", encoding="utf-8") as fh:
            w = csv.writer(fh)
            w.writerow(["city", "year"] + FIELDS)
            for city in CITIES:
                for yr in YEARS:
                    row = tbl.get((city, yr), {})
                    w.writerow([city, yr] + [row.get(f, "") for f in FIELDS])

    write(WORK / "data" / "panel.csv", table)

    # 严格口径面板（预注册里的主分析口径）：同一城市在**实际进入分析的那些年份**里
    # 口径必须一致，不一致的城市该字段整列按缺失处理。
    # 判定只看「其他字段齐全、真能进分析」的那些行 —— 缺别的字段本来就要整行剔除，
    # 让它们参与口径判定等于用剔掉的行去否决留下的行。
    usable = {k for k in table if all(table[k].get(f) is not None for f in FIELDS)}
    strict = {k: dict(v) for k, v in table.items()}
    dropped = []
    for city in CITIES:
        for field in FIELDS:
            cals = {r.get("caliber") for r in prov["records"]
                    if r["city"] == city and r["field"] == field
                    and (r["city"], int(r["year"])) in usable}
            cals.discard(None)
            if len(cals) > 1:
                dropped.append({"city": city, "field": field, "calibers": sorted(cals)})
                for yr in YEARS:
                    strict.get((city, yr), {}).pop(field, None)
    write(WORK / "data" / "panel_strict.csv", strict)
    filled = {f: sum(1 for c in CITIES for y in YEARS if table.get((c, y), {}).get(f) is not None)
              for f in FIELDS}
    complete = sum(1 for c in CITIES for y in YEARS
                   if all(table.get((c, y), {}).get(f) is not None for f in FIELDS))
    complete_strict = sum(1 for c in CITIES for y in YEARS
                          if all(strict.get((c, y), {}).get(f) is not None for f in FIELDS))
    summary = {"cells_filled": filled,
               "complete_city_years_all": complete,
               "complete_city_years_strict_caliber": complete_strict,
               "complete_rows": sorted(f"{c}{y}" for c in CITIES for y in YEARS
                                       if all(table.get((c, y), {}).get(f) is not None
                                              for f in FIELDS)),
               "dropped_for_caliber_mismatch": dropped,
               "total_possible": len(CITIES) * len(YEARS)}
    (WORK / "data" / "panel_summary.json").write_text(
        json.dumps(summary, ensure_ascii=False, indent=1), encoding="utf-8")
    print(json.dumps(summary, ensure_ascii=False, indent=1))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
