# -*- coding: utf-8 -*-
"""
전국 매칭키(PNU) + 세그먼트 생성 (벡터화, 대용량용)
===================================================
입력 : 결과/전국/실거래가_{아파트_매매, 연립다세대_매매}.csv (약 320만 행)
출력 : 결과/전국/분석_실거래가_매칭키.csv

로직은 match.py와 동일하나 320만 행을 위해 벡터화:
  PNU(19) = 법정동코드(10) + 대장구분(1) + 본번(4) + 부번(4)
  - 아파트: sggCd+umdCd+landCd+bonbun+bubun 직접
  - 연립  : umdCd는 아파트에서 만든 (sggCd,umdNm)→umdCd 사전으로 보완,
            본번/부번은 jibun 파싱 (마스킹 '*' 포함 시 제외)
"""
from __future__ import annotations

import sys
from pathlib import Path

import numpy as np
import pandas as pd

from match import add_segments, build_umd_lookup  # 재사용

try:
    sys.stdout.reconfigure(encoding="utf-8")
except Exception:
    pass

NAT = Path(__file__).with_name("결과") / "전국"
FILES = {
    "아파트_매매": NAT / "실거래가_아파트_매매.csv",
    "연립다세대_매매": NAT / "실거래가_연립다세대_매매.csv",
}


def _digits(s: pd.Series) -> pd.Series:
    return s.astype("string").str.replace(r"\D", "", regex=True)


def build_pnu_vec(df: pd.DataFrame, umd_lookup: dict) -> pd.Series:
    n = len(df)
    sgg = _digits(df["sggCd"]).str.zfill(5)

    # 읍면동코드
    if "umdCd" in df:
        umd = _digits(df["umdCd"])
        umd = umd.where(umd.str.len() > 0)
    else:
        umd = pd.Series(pd.NA, index=df.index, dtype="string")
    need = umd.isna()
    if need.any() and "umdNm" in df:
        keys = list(zip(sgg[need].tolist(), df.loc[need, "umdNm"].astype(str).tolist()))
        filled = [umd_lookup.get(k) for k in keys]
        umd.loc[need] = pd.array(filled, dtype="string")
    umd = umd.where(umd.notna()).str.zfill(5)

    # 대장구분(끝 1자리), 기본 '1'
    if "landCd" in df:
        land = _digits(df["landCd"])
        land = land.where(land.str.len() > 0, "1").str[-1]
    else:
        land = pd.Series("1", index=df.index, dtype="string")

    # 본번/부번
    bon = _digits(df["bonbun"]) if "bonbun" in df else pd.Series(pd.NA, index=df.index, dtype="string")
    bub = _digits(df["bubun"]) if "bubun" in df else pd.Series(pd.NA, index=df.index, dtype="string")
    need_j = bon.isna() | (bon.str.len() == 0)
    if need_j.any() and "jibun" in df:
        jj = df.loc[need_j, "jibun"].astype(str)
        jj = jj.where(~jj.str.contains(r"\*", na=False))      # 마스킹 제외
        ext = jj.str.extract(r"(\d+)(?:-(\d+))?")
        bon.loc[need_j] = ext[0]
        bub.loc[need_j] = ext[1]
    bub = bub.where(bub.notna() & (bub.str.len() > 0), "0")

    ok = sgg.notna() & umd.notna() & bon.notna() & (bon.str.len() > 0)
    pnu = pd.Series(pd.NA, index=df.index, dtype="string")
    pnu[ok] = (sgg[ok] + umd[ok] + land[ok] + bon[ok].str.zfill(4) + bub[ok].str.zfill(4))
    return pnu


def main() -> None:
    frames = {}
    for name, path in FILES.items():
        if not path.exists():
            print(f"  (없음) {path}")
            continue
        print(f"로딩: {name} ...", flush=True)
        df = pd.read_csv(path, dtype=str, low_memory=False)
        df["자료구분"] = name
        frames[name] = df
        print(f"  {name}: {len(df):,}행")

    umd_lookup = build_umd_lookup(*frames.values())
    print(f"읍면동코드 사전: {len(umd_lookup):,}개 (sggCd,umdNm) 매핑")

    out = []
    for name, df in frames.items():
        df = add_segments(df)
        df["PNU"] = build_pnu_vec(df, umd_lookup)
        ok = df["PNU"].notna().sum()
        print(f"  {name}: {len(df):,}행 | PNU {ok:,} ({100*ok/len(df):.1f}%)")
        out.append(df)

    full = pd.concat(out, ignore_index=True)
    keep = ["자료구분", "PNU", "sggCd", "umdNm", "jibun", "aptNm", "mhouseNm",
            "전용면적_㎡", "면적구간", "floor", "거래금액_원", "평단가_만원",
            "거래연도", "거래분기", "공시기준연도", "buildYear", "dealDay"]
    keep = [c for c in keep if c in full.columns]
    analysis = full[keep]
    outp = NAT / "분석_실거래가_매칭키.csv"
    analysis.to_csv(outp, index=False, encoding="utf-8-sig")
    print(f"\n저장: {outp} ({len(analysis):,}행)")

    # 공시가격 수집 규모 산정: (유형, 연도)별 고유 PNU
    print("\n[전국 고유 PNU — VWorld 공시가격 수집 규모]")
    full["거래연도"] = pd.to_numeric(full["거래연도"], errors="coerce")
    grand = 0
    for name in frames:
        sub = full[(full["자료구분"] == name) & full["PNU"].notna()]
        s = 0
        for y in range(2019, 2027):
            s += sub[sub["거래연도"] == y]["PNU"].nunique()
        print(f"  {name}: (PNU,연도) 쌍 합계 {s:,} | 고유 PNU {sub['PNU'].nunique():,}")
        grand += s
    print(f"  => 전국 VWorld 호출 추정 ~{grand:,}건")


if __name__ == "__main__":
    main()
