"""
ECOS 거시경제변수 포괄 수집기 — CSV 캐싱

목적:
  - ECOS API에서 30+ 거시경제변수 수집
  - 수집 결과를 data/cache/macro_ecos.csv에 저장
  - 이미 캐시가 있으면 API 호출하지 않고 캐시 사용
  - --force 옵션으로 캐시 갱신 가능

사용:
  python data/ecos_fetcher.py              # 캐시 있으면 skip
  python data/ecos_fetcher.py --force      # 캐시 무시하고 API 재수집
  python data/ecos_fetcher.py --no-api     # API 없이 fallback만 사용
"""

import sys, io, time, argparse, json
import numpy as np, pandas as pd
from pathlib import Path

if sys.stdout.encoding != 'utf-8':
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')

sys.path.insert(0, str(Path(__file__).parent.parent))

CACHE_DIR = Path(__file__).parent / "cache"
CACHE_FILE = CACHE_DIR / "macro_ecos.csv"

# ============================================================
# ECOS 변수 정의 (stat_code, period, item_code, 변수명, 월→연 집계법)
# ============================================================
ECOS_VARIABLES = [
    # --- 성장 ---
    {"name": "GDP_GROWTH",    "stat": "200Y002", "period": "A", "item": "10111",  "agg": None,     "desc": "GDP 실질성장률 (%)"},
    
    # --- 고용 ---
    {"name": "UNEMPLOYMENT",  "stat": "901Y027", "period": "M", "item": "I16AA",  "agg": "mean",   "desc": "실업률 (%)"},
    
    # --- 금리 ---
    {"name": "BASE_RATE",     "stat": "722Y001", "period": "M", "item": "0101000", "agg": "last",  "desc": "한은 기준금리 (%)"},
    {"name": "CD_RATE",       "stat": "817Y002", "period": "M", "item": "010502000", "agg": "mean", "desc": "CD 91일 금리 (%)"},
    {"name": "GOVT_3Y",       "stat": "817Y002", "period": "M", "item": "010200000", "agg": "mean", "desc": "국고채 3년 금리 (%)"},
    {"name": "GOVT_10Y",      "stat": "817Y002", "period": "M", "item": "010210000", "agg": "mean", "desc": "국고채 10년 금리 (%)"},
    {"name": "CORP_AA",       "stat": "817Y002", "period": "M", "item": "010300000", "agg": "mean", "desc": "회사채 AA- 금리 (%)"},
    {"name": "CORP_BBB",      "stat": "817Y002", "period": "M", "item": "010400000", "agg": "mean", "desc": "회사채 BBB- 금리 (%)"},
    
    # --- 물가 ---
    {"name": "CPI_GROWTH",    "stat": "901Y009", "period": "A", "item": "0",      "agg": None,     "desc": "소비자물가 상승률 (%)"},
    {"name": "IMPORT_PRICE",  "stat": "404Y014", "period": "M", "item": "AA00",   "agg": "mean",   "desc": "수입물가지수 (원화기준)"},
    {"name": "PPI",           "stat": "404Y014", "period": "M", "item": "AA00",   "agg": "mean",   "desc": "생산자물가지수"},  # 별도 확인 필요
    
    # --- 경기지수 ---
    {"name": "LEADING_INDEX", "stat": "901Y067", "period": "M", "item": "I16A",   "agg": "mean",   "desc": "경기선행종합지수"},
    {"name": "COINCIDENT",    "stat": "901Y067", "period": "M", "item": "I16B",   "agg": "mean",   "desc": "경기동행종합지수"},
    {"name": "CSI",           "stat": "901Y068", "period": "M", "item": "I16A",   "agg": "mean",   "desc": "소비자심리지수 (CCSI)"},
    {"name": "BSI_MANUF",     "stat": "512Y014", "period": "M", "item": "99BA",   "agg": "mean",   "desc": "제조업 BSI (전망)"},
    
    # --- 생산/교역 ---
    {"name": "IPI",           "stat": "901Y033", "period": "M", "item": "I11A",   "agg": "mean",   "desc": "광공업생산지수"},
    {"name": "SPI",           "stat": "901Y033", "period": "M", "item": "I31A",   "agg": "mean",   "desc": "서비스업생산지수"},
    {"name": "EXPORT",        "stat": "403Y001", "period": "A", "item": "1",      "agg": None,     "desc": "수출 (백만달러)"},
    {"name": "IMPORT_AMT",    "stat": "403Y001", "period": "A", "item": "2",      "agg": None,     "desc": "수입 (백만달러)"},
    
    # --- 환율/유가 ---
    {"name": "USDKRW",       "stat": "036Y001", "period": "M", "item": "0000001", "agg": "mean",   "desc": "원/달러 환율 (종가평균)"},
    
    # --- 통화/유동성 ---
    {"name": "M2",            "stat": "101Y003", "period": "M", "item": "BBGA00",  "agg": "last",  "desc": "M2 광의통화 (조원)"},
    
    # --- 부도/신용 ---
    {"name": "DISHONOR_RATE", "stat": "104Y016", "period": "M", "item": "010000",  "agg": "mean",  "desc": "어음부도율 (%)"},
    {"name": "DISHONOR_AMT",  "stat": "104Y016", "period": "M", "item": "020000",  "agg": "sum",   "desc": "부도금액 (억원)"},
    
    # --- 주식 ---
    {"name": "KOSPI",         "stat": "802Y001", "period": "M", "item": "0001000", "agg": "mean",   "desc": "KOSPI 종합주가지수"},
    
    # --- 부동산/건설 ---
    {"name": "HOUSING_PRICE", "stat": "901Y062", "period": "M", "item": "P00",     "agg": "mean",  "desc": "전국 주택매매가격지수"},
    {"name": "CONSTRUCTION",  "stat": "512Y010", "period": "M", "item": "10AA",    "agg": "sum",   "desc": "건설수주액 (억원)"},
    
    # --- 가계 ---
    {"name": "HOUSEHOLD_DEBT","stat": "151Y001", "period": "Q", "item": "A11",     "agg": "last",  "desc": "가계부채 (조원)"},

    # --- 투자/저축 (2.1.1.1 주요지표 연간) ---
    {"name": "CONSTR_INVEST",  "stat": "200Y002", "period": "A", "item": "10315",  "agg": None,   "desc": "건설투자 증감률 (%)"},
    {"name": "GFCF_GROWTH",    "stat": "200Y002", "period": "A", "item": "10311",  "agg": None,   "desc": "총고정자본형성 증감률 (%)"},
    {"name": "SAVING_RATE",    "stat": "200Y002", "period": "A", "item": "10903",  "agg": None,   "desc": "총저축률 (%)"},
    {"name": "INVEST_RATE",    "stat": "200Y002", "period": "A", "item": "10904",  "agg": None,   "desc": "국내총투자율 (%)"},
    {"name": "TRADE_GNI",      "stat": "200Y002", "period": "A", "item": "10910",  "agg": None,   "desc": "수출입의 대 GNI 비율 (%)"},

    # --- 제조업 (8.3.7) ---
    {"name": "MANUF_CAPACITY",  "stat": "901Y033", "period": "M", "item": "I21A",  "agg": "mean",  "desc": "제조업 평균가동률 (2020=100)"},
]


# ============================================================
# Fallback 데이터 (API 없이도 작동) — 31개 변수, 26년
# ============================================================
# 추가 변수 설명:
#   FACILITY_INVEST: 설비투자지수 (2020=100)
#   RETAIL_SALES:    소매판매액지수 (2020=100)
#   CURRENT_ACCOUNT: 경상수지 (억달러)
#   EMPLOYED:        취업자수 (만명)
#   EMPLOYMENT_RATE: 고용률 15-64세 (%)
#   OIL_PRICE:       두바이유 연평균 ($/배럴) — 한국 수입유 기준
#   COINCIDENT:      경기동행종합지수
#   BSI_MANUF:       제조업 BSI 전망
#   CONSTRUCTION_DONE: 건설기성액 (조원)
#   SPI:             서비스업생산지수 (2020=100)

def _build_fallback() -> pd.DataFrame:
    """API 없이 작동하는 확장 fallback — 37개 변수"""
    # fmt: off
    data = {
        2000: {"GDP_GROWTH":8.9,"UNEMPLOYMENT":4.4,"BASE_RATE":5.25,"CD_RATE":7.09,"CPI_GROWTH":2.3,"LEADING_INDEX":101.2,"GOVT_3Y":8.35,"GOVT_10Y":8.55,"CORP_AA":9.35,"CORP_BBB":11.90,"IPI":102.5,"EXPORT":172268,"IMPORT_AMT":160481,"USDKRW":1131,"M2":651.8,"CSI":101.0,"KOSPI":504,"IMPORT_PRICE":78.5,"DISHONOR_RATE":0.46,"HOUSING_PRICE":55.2,"HOUSEHOLD_DEBT":194.0,
               "FACILITY_INVEST":62.5,"RETAIL_SALES":72.0,"CURRENT_ACCOUNT":123.5,"EMPLOYED":2115,"EMPLOYMENT_RATE":58.5,"OIL_PRICE":26.2,"COINCIDENT":99.8,"BSI_MANUF":90,"CONSTRUCTION_DONE":56.3,"SPI":58.0,"CONSTR_INVEST_GR":-1.4,"GFCF_GROWTH":11.4,"SAVING_RATE":33.7,"INVEST_RATE":31.0,"TRADE_GNI":72.5,"MANUF_CAPACITY":109.5},
        2001: {"GDP_GROWTH":4.5,"UNEMPLOYMENT":4.0,"BASE_RATE":4.00,"CD_RATE":5.34,"CPI_GROWTH":4.1,"LEADING_INDEX":99.5,"GOVT_3Y":6.70,"GOVT_10Y":7.05,"CORP_AA":8.12,"CORP_BBB":11.27,"IPI":99.5,"EXPORT":150439,"IMPORT_AMT":141098,"USDKRW":1291,"M2":736.5,"CSI":96.5,"KOSPI":694,"IMPORT_PRICE":73.6,"DISHONOR_RATE":0.28,"HOUSING_PRICE":56.8,"HOUSEHOLD_DEBT":225.0,
               "FACILITY_INVEST":58.5,"RETAIL_SALES":73.5,"CURRENT_ACCOUNT":80.3,"EMPLOYED":2118,"EMPLOYMENT_RATE":59.0,"OIL_PRICE":22.8,"COINCIDENT":98.0,"BSI_MANUF":82,"CONSTRUCTION_DONE":53.8,"SPI":60.2,"CONSTR_INVEST_GR":5.6,"GFCF_GROWTH":0.6,"SAVING_RATE":31.7,"INVEST_RATE":29.3,"TRADE_GNI":66.3,"MANUF_CAPACITY":105.8},
        2002: {"GDP_GROWTH":7.4,"UNEMPLOYMENT":3.3,"BASE_RATE":4.25,"CD_RATE":4.99,"CPI_GROWTH":2.8,"LEADING_INDEX":102.3,"GOVT_3Y":6.06,"GOVT_10Y":6.58,"CORP_AA":7.02,"CORP_BBB":9.75,"IPI":108.5,"EXPORT":162471,"IMPORT_AMT":152126,"USDKRW":1251,"M2":816.3,"CSI":105.0,"KOSPI":628,"IMPORT_PRICE":72.1,"DISHONOR_RATE":0.18,"HOUSING_PRICE":65.3,"HOUSEHOLD_DEBT":306.0,
               "FACILITY_INVEST":63.2,"RETAIL_SALES":76.0,"CURRENT_ACCOUNT":53.9,"EMPLOYED":2217,"EMPLOYMENT_RATE":60.0,"OIL_PRICE":23.7,"COINCIDENT":101.5,"BSI_MANUF":92,"CONSTRUCTION_DONE":55.2,"SPI":63.5,"CONSTR_INVEST_GR":6.5,"GFCF_GROWTH":6.7,"SAVING_RATE":31.3,"INVEST_RATE":29.1,"TRADE_GNI":62.4,"MANUF_CAPACITY":110.5},
        2003: {"GDP_GROWTH":2.9,"UNEMPLOYMENT":3.6,"BASE_RATE":3.75,"CD_RATE":4.24,"CPI_GROWTH":3.5,"LEADING_INDEX":98.8,"GOVT_3Y":4.93,"GOVT_10Y":5.45,"CORP_AA":5.70,"CORP_BBB":8.97,"IPI":109.8,"EXPORT":193817,"IMPORT_AMT":178827,"USDKRW":1192,"M2":879.2,"CSI":96.0,"KOSPI":811,"IMPORT_PRICE":81.3,"DISHONOR_RATE":0.12,"HOUSING_PRICE":71.5,"HOUSEHOLD_DEBT":360.0,
               "FACILITY_INVEST":60.5,"RETAIL_SALES":74.0,"CURRENT_ACCOUNT":119.5,"EMPLOYED":2212,"EMPLOYMENT_RATE":59.5,"OIL_PRICE":26.8,"COINCIDENT":99.2,"BSI_MANUF":85,"CONSTRUCTION_DONE":58.0,"SPI":64.8,"CONSTR_INVEST_GR":10.0,"GFCF_GROWTH":4.0,"SAVING_RATE":32.6,"INVEST_RATE":30.0,"TRADE_GNI":65.0,"MANUF_CAPACITY":108.2},
        2004: {"GDP_GROWTH":4.9,"UNEMPLOYMENT":3.7,"BASE_RATE":3.25,"CD_RATE":3.77,"CPI_GROWTH":3.6,"LEADING_INDEX":100.5,"GOVT_3Y":4.11,"GOVT_10Y":4.73,"CORP_AA":4.72,"CORP_BBB":7.53,"IPI":119.2,"EXPORT":253845,"IMPORT_AMT":224463,"USDKRW":1145,"M2":935.3,"CSI":97.0,"KOSPI":896,"IMPORT_PRICE":90.5,"DISHONOR_RATE":0.08,"HOUSING_PRICE":71.0,"HOUSEHOLD_DEBT":394.0,
               "FACILITY_INVEST":66.5,"RETAIL_SALES":74.5,"CURRENT_ACCOUNT":284.2,"EMPLOYED":2272,"EMPLOYMENT_RATE":59.8,"OIL_PRICE":33.5,"COINCIDENT":100.8,"BSI_MANUF":88,"CONSTRUCTION_DONE":63.5,"SPI":66.0,"CONSTR_INVEST_GR":1.8,"GFCF_GROWTH":2.1,"SAVING_RATE":34.8,"INVEST_RATE":30.3,"TRADE_GNI":73.5,"MANUF_CAPACITY":113.8},
        2005: {"GDP_GROWTH":3.9,"UNEMPLOYMENT":3.7,"BASE_RATE":3.75,"CD_RATE":3.81,"CPI_GROWTH":2.8,"LEADING_INDEX":101.8,"GOVT_3Y":4.27,"GOVT_10Y":4.95,"CORP_AA":4.68,"CORP_BBB":6.51,"IPI":126.0,"EXPORT":284419,"IMPORT_AMT":261238,"USDKRW":1024,"M2":1002.7,"CSI":100.5,"KOSPI":1011,"IMPORT_PRICE":99.2,"DISHONOR_RATE":0.06,"HOUSING_PRICE":73.5,"HOUSEHOLD_DEBT":440.0,
               "FACILITY_INVEST":68.0,"RETAIL_SALES":76.5,"CURRENT_ACCOUNT":149.8,"EMPLOYED":2297,"EMPLOYMENT_RATE":60.3,"OIL_PRICE":49.3,"COINCIDENT":101.2,"BSI_MANUF":92,"CONSTRUCTION_DONE":66.0,"SPI":68.5,"CONSTR_INVEST_GR":-0.4,"GFCF_GROWTH":1.9,"SAVING_RATE":33.4,"INVEST_RATE":29.7,"TRADE_GNI":72.5,"MANUF_CAPACITY":114.5},
        2006: {"GDP_GROWTH":5.2,"UNEMPLOYMENT":3.5,"BASE_RATE":4.50,"CD_RATE":4.72,"CPI_GROWTH":2.2,"LEADING_INDEX":102.5,"GOVT_3Y":4.83,"GOVT_10Y":5.17,"CORP_AA":5.25,"CORP_BBB":7.08,"IPI":136.0,"EXPORT":325465,"IMPORT_AMT":309383,"USDKRW":955,"M2":1089.9,"CSI":106.0,"KOSPI":1434,"IMPORT_PRICE":107.8,"DISHONOR_RATE":0.05,"HOUSING_PRICE":80.2,"HOUSEHOLD_DEBT":497.0,
               "FACILITY_INVEST":73.5,"RETAIL_SALES":78.5,"CURRENT_ACCOUNT":53.9,"EMPLOYED":2334,"EMPLOYMENT_RATE":60.9,"OIL_PRICE":61.5,"COINCIDENT":102.8,"BSI_MANUF":95,"CONSTRUCTION_DONE":69.5,"SPI":71.2,"CONSTR_INVEST_GR":0.5,"GFCF_GROWTH":3.4,"SAVING_RATE":32.5,"INVEST_RATE":29.6,"TRADE_GNI":73.2,"MANUF_CAPACITY":115.8},
        2007: {"GDP_GROWTH":5.5,"UNEMPLOYMENT":3.2,"BASE_RATE":5.00,"CD_RATE":5.36,"CPI_GROWTH":2.5,"LEADING_INDEX":103.1,"GOVT_3Y":5.23,"GOVT_10Y":5.42,"CORP_AA":5.70,"CORP_BBB":7.44,"IPI":144.5,"EXPORT":371489,"IMPORT_AMT":356846,"USDKRW":929,"M2":1181.6,"CSI":108.5,"KOSPI":1897,"IMPORT_PRICE":109.3,"DISHONOR_RATE":0.04,"HOUSING_PRICE":83.5,"HOUSEHOLD_DEBT":560.0,
               "FACILITY_INVEST":78.5,"RETAIL_SALES":80.0,"CURRENT_ACCOUNT":59.5,"EMPLOYED":2371,"EMPLOYMENT_RATE":61.3,"OIL_PRICE":68.4,"COINCIDENT":103.5,"BSI_MANUF":97,"CONSTRUCTION_DONE":72.8,"SPI":74.0,"CONSTR_INVEST_GR":1.4,"GFCF_GROWTH":4.2,"SAVING_RATE":32.4,"INVEST_RATE":29.4,"TRADE_GNI":77.8,"MANUF_CAPACITY":115.2},
        2008: {"GDP_GROWTH":2.8,"UNEMPLOYMENT":3.2,"BASE_RATE":3.00,"CD_RATE":5.70,"CPI_GROWTH":4.7,"LEADING_INDEX":96.5,"GOVT_3Y":5.27,"GOVT_10Y":5.57,"CORP_AA":7.02,"CORP_BBB":10.73,"IPI":148.2,"EXPORT":422007,"IMPORT_AMT":435275,"USDKRW":1103,"M2":1263.2,"CSI":86.0,"KOSPI":1124,"IMPORT_PRICE":132.5,"DISHONOR_RATE":0.11,"HOUSING_PRICE":84.0,"HOUSEHOLD_DEBT":630.0,
               "FACILITY_INVEST":76.0,"RETAIL_SALES":79.0,"CURRENT_ACCOUNT":-57.8,"EMPLOYED":2385,"EMPLOYMENT_RATE":61.5,"OIL_PRICE":94.3,"COINCIDENT":98.5,"BSI_MANUF":72,"CONSTRUCTION_DONE":74.5,"SPI":75.5,"CONSTR_INVEST_GR":-2.8,"GFCF_GROWTH":-1.9,"SAVING_RATE":31.5,"INVEST_RATE":31.2,"TRADE_GNI":96.5,"MANUF_CAPACITY":112.8},
        2009: {"GDP_GROWTH":0.8,"UNEMPLOYMENT":3.6,"BASE_RATE":2.00,"CD_RATE":2.63,"CPI_GROWTH":2.8,"LEADING_INDEX":98.2,"GOVT_3Y":4.04,"GOVT_10Y":4.85,"CORP_AA":5.80,"CORP_BBB":9.24,"IPI":140.0,"EXPORT":363534,"IMPORT_AMT":323085,"USDKRW":1276,"M2":1404.4,"CSI":85.0,"KOSPI":1683,"IMPORT_PRICE":104.2,"DISHONOR_RATE":0.10,"HOUSING_PRICE":84.8,"HOUSEHOLD_DEBT":694.0,
               "FACILITY_INVEST":60.5,"RETAIL_SALES":77.5,"CURRENT_ACCOUNT":328.1,"EMPLOYED":2355,"EMPLOYMENT_RATE":60.1,"OIL_PRICE":61.8,"COINCIDENT":96.5,"BSI_MANUF":68,"CONSTRUCTION_DONE":68.2,"SPI":76.0,"CONSTR_INVEST_GR":0.2,"GFCF_GROWTH":-1.0,"SAVING_RATE":31.4,"INVEST_RATE":26.3,"TRADE_GNI":82.0,"MANUF_CAPACITY":102.5},
        2010: {"GDP_GROWTH":6.8,"UNEMPLOYMENT":3.7,"BASE_RATE":2.50,"CD_RATE":2.80,"CPI_GROWTH":2.9,"LEADING_INDEX":103.0,"GOVT_3Y":3.72,"GOVT_10Y":4.49,"CORP_AA":4.66,"CORP_BBB":7.98,"IPI":161.5,"EXPORT":466384,"IMPORT_AMT":425212,"USDKRW":1156,"M2":1504.3,"CSI":107.0,"KOSPI":2051,"IMPORT_PRICE":115.8,"DISHONOR_RATE":0.06,"HOUSING_PRICE":87.0,"HOUSEHOLD_DEBT":776.0,
               "FACILITY_INVEST":80.5,"RETAIL_SALES":80.5,"CURRENT_ACCOUNT":282.1,"EMPLOYED":2397,"EMPLOYMENT_RATE":60.4,"OIL_PRICE":78.1,"COINCIDENT":103.0,"BSI_MANUF":95,"CONSTRUCTION_DONE":72.0,"SPI":78.5,"CONSTR_INVEST_GR":-1.4,"GFCF_GROWTH":5.8,"SAVING_RATE":33.5,"INVEST_RATE":29.5,"TRADE_GNI":87.9,"MANUF_CAPACITY":113.0},
        2011: {"GDP_GROWTH":3.7,"UNEMPLOYMENT":3.4,"BASE_RATE":3.25,"CD_RATE":3.55,"CPI_GROWTH":4.0,"LEADING_INDEX":101.2,"GOVT_3Y":3.62,"GOVT_10Y":4.05,"CORP_AA":4.41,"CORP_BBB":7.75,"IPI":168.0,"EXPORT":555214,"IMPORT_AMT":524413,"USDKRW":1108,"M2":1586.5,"CSI":100.0,"KOSPI":1826,"IMPORT_PRICE":130.2,"DISHONOR_RATE":0.05,"HOUSING_PRICE":89.5,"HOUSEHOLD_DEBT":857.0,
               "FACILITY_INVEST":82.0,"RETAIL_SALES":82.0,"CURRENT_ACCOUNT":184.1,"EMPLOYED":2424,"EMPLOYMENT_RATE":60.7,"OIL_PRICE":106.0,"COINCIDENT":102.5,"BSI_MANUF":90,"CONSTRUCTION_DONE":73.5,"SPI":80.0,"CONSTR_INVEST_GR":-4.9,"GFCF_GROWTH":0.8,"SAVING_RATE":34.0,"INVEST_RATE":29.4,"TRADE_GNI":96.7,"MANUF_CAPACITY":112.5},
        2012: {"GDP_GROWTH":2.4,"UNEMPLOYMENT":3.2,"BASE_RATE":2.75,"CD_RATE":3.13,"CPI_GROWTH":2.2,"LEADING_INDEX":100.3,"GOVT_3Y":3.13,"GOVT_10Y":3.35,"CORP_AA":3.76,"CORP_BBB":6.56,"IPI":168.2,"EXPORT":547870,"IMPORT_AMT":519584,"USDKRW":1127,"M2":1673.5,"CSI":100.5,"KOSPI":1997,"IMPORT_PRICE":123.5,"DISHONOR_RATE":0.04,"HOUSING_PRICE":89.0,"HOUSEHOLD_DEBT":934.0,
               "FACILITY_INVEST":79.0,"RETAIL_SALES":83.5,"CURRENT_ACCOUNT":508.4,"EMPLOYED":2468,"EMPLOYMENT_RATE":61.3,"OIL_PRICE":109.1,"COINCIDENT":100.5,"BSI_MANUF":85,"CONSTRUCTION_DONE":72.0,"SPI":82.5,"CONSTR_INVEST_GR":-3.2,"GFCF_GROWTH":-0.5,"SAVING_RATE":33.8,"INVEST_RATE":28.4,"TRADE_GNI":96.8,"MANUF_CAPACITY":110.2},
        2013: {"GDP_GROWTH":3.2,"UNEMPLOYMENT":3.1,"BASE_RATE":2.50,"CD_RATE":2.72,"CPI_GROWTH":1.3,"LEADING_INDEX":100.8,"GOVT_3Y":2.79,"GOVT_10Y":3.28,"CORP_AA":3.19,"CORP_BBB":5.87,"IPI":168.8,"EXPORT":559632,"IMPORT_AMT":515586,"USDKRW":1095,"M2":1756.2,"CSI":103.0,"KOSPI":2011,"IMPORT_PRICE":115.0,"DISHONOR_RATE":0.04,"HOUSING_PRICE":88.8,"HOUSEHOLD_DEBT":980.0,
               "FACILITY_INVEST":77.5,"RETAIL_SALES":85.0,"CURRENT_ACCOUNT":812.1,"EMPLOYED":2503,"EMPLOYMENT_RATE":61.6,"OIL_PRICE":105.5,"COINCIDENT":101.0,"BSI_MANUF":88,"CONSTRUCTION_DONE":71.5,"SPI":84.0,"CONSTR_INVEST_GR":5.4,"GFCF_GROWTH":3.3,"SAVING_RATE":34.0,"INVEST_RATE":28.7,"TRADE_GNI":93.2,"MANUF_CAPACITY":108.0},
        2014: {"GDP_GROWTH":3.2,"UNEMPLOYMENT":3.5,"BASE_RATE":2.00,"CD_RATE":2.36,"CPI_GROWTH":1.3,"LEADING_INDEX":101.0,"GOVT_3Y":2.56,"GOVT_10Y":2.92,"CORP_AA":2.99,"CORP_BBB":5.22,"IPI":168.5,"EXPORT":572665,"IMPORT_AMT":525515,"USDKRW":1053,"M2":1871.0,"CSI":104.0,"KOSPI":1916,"IMPORT_PRICE":105.6,"DISHONOR_RATE":0.04,"HOUSING_PRICE":90.2,"HOUSEHOLD_DEBT":1050.0,
               "FACILITY_INVEST":81.0,"RETAIL_SALES":86.5,"CURRENT_ACCOUNT":843.5,"EMPLOYED":2546,"EMPLOYMENT_RATE":62.4,"OIL_PRICE":96.7,"COINCIDENT":101.5,"BSI_MANUF":90,"CONSTRUCTION_DONE":73.8,"SPI":86.0,"CONSTR_INVEST_GR":1.1,"GFCF_GROWTH":3.1,"SAVING_RATE":34.5,"INVEST_RATE":29.0,"TRADE_GNI":87.6,"MANUF_CAPACITY":108.8},
        2015: {"GDP_GROWTH":2.8,"UNEMPLOYMENT":3.6,"BASE_RATE":1.50,"CD_RATE":1.72,"CPI_GROWTH":0.7,"LEADING_INDEX":100.5,"GOVT_3Y":1.80,"GOVT_10Y":2.25,"CORP_AA":2.18,"CORP_BBB":4.61,"IPI":168.0,"EXPORT":526757,"IMPORT_AMT":436499,"USDKRW":1131,"M2":2010.0,"CSI":103.5,"KOSPI":1961,"IMPORT_PRICE":79.5,"DISHONOR_RATE":0.03,"HOUSING_PRICE":95.0,"HOUSEHOLD_DEBT":1145.0,
               "FACILITY_INVEST":84.5,"RETAIL_SALES":88.0,"CURRENT_ACCOUNT":1059.4,"EMPLOYED":2567,"EMPLOYMENT_RATE":62.6,"OIL_PRICE":51.2,"COINCIDENT":101.0,"BSI_MANUF":86,"CONSTRUCTION_DONE":77.5,"SPI":88.5,"CONSTR_INVEST_GR":9.1,"GFCF_GROWTH":5.1,"SAVING_RATE":36.0,"INVEST_RATE":28.8,"TRADE_GNI":79.8,"MANUF_CAPACITY":107.2},
        2016: {"GDP_GROWTH":2.9,"UNEMPLOYMENT":3.7,"BASE_RATE":1.25,"CD_RATE":1.48,"CPI_GROWTH":1.0,"LEADING_INDEX":99.8,"GOVT_3Y":1.44,"GOVT_10Y":1.80,"CORP_AA":1.88,"CORP_BBB":4.60,"IPI":168.5,"EXPORT":495426,"IMPORT_AMT":406193,"USDKRW":1161,"M2":2151.1,"CSI":100.0,"KOSPI":2026,"IMPORT_PRICE":78.0,"DISHONOR_RATE":0.03,"HOUSING_PRICE":97.5,"HOUSEHOLD_DEBT":1250.0,
               "FACILITY_INVEST":82.0,"RETAIL_SALES":89.5,"CURRENT_ACCOUNT":992.4,"EMPLOYED":2597,"EMPLOYMENT_RATE":63.0,"OIL_PRICE":41.3,"COINCIDENT":100.2,"BSI_MANUF":85,"CONSTRUCTION_DONE":89.5,"SPI":90.0,"CONSTR_INVEST_GR":10.3,"GFCF_GROWTH":5.6,"SAVING_RATE":36.4,"INVEST_RATE":29.2,"TRADE_GNI":74.5,"MANUF_CAPACITY":106.0},
        2017: {"GDP_GROWTH":3.2,"UNEMPLOYMENT":3.7,"BASE_RATE":1.50,"CD_RATE":1.52,"CPI_GROWTH":1.9,"LEADING_INDEX":101.5,"GOVT_3Y":1.80,"GOVT_10Y":2.33,"CORP_AA":2.28,"CORP_BBB":4.83,"IPI":174.2,"EXPORT":573694,"IMPORT_AMT":478478,"USDKRW":1131,"M2":2347.2,"CSI":105.0,"KOSPI":2467,"IMPORT_PRICE":90.5,"DISHONOR_RATE":0.02,"HOUSING_PRICE":100.0,"HOUSEHOLD_DEBT":1364.0,
               "FACILITY_INVEST":92.0,"RETAIL_SALES":92.0,"CURRENT_ACCOUNT":752.6,"EMPLOYED":2620,"EMPLOYMENT_RATE":63.2,"OIL_PRICE":53.1,"COINCIDENT":101.8,"BSI_MANUF":92,"CONSTRUCTION_DONE":90.0,"SPI":92.5,"CONSTR_INVEST_GR":7.3,"GFCF_GROWTH":9.8,"SAVING_RATE":36.6,"INVEST_RATE":31.1,"TRADE_GNI":77.3,"MANUF_CAPACITY":107.5},
        2018: {"GDP_GROWTH":2.9,"UNEMPLOYMENT":3.8,"BASE_RATE":1.75,"CD_RATE":1.85,"CPI_GROWTH":1.5,"LEADING_INDEX":100.8,"GOVT_3Y":2.10,"GOVT_10Y":2.56,"CORP_AA":2.67,"CORP_BBB":5.41,"IPI":178.0,"EXPORT":604860,"IMPORT_AMT":535202,"USDKRW":1100,"M2":2508.9,"CSI":102.0,"KOSPI":2041,"IMPORT_PRICE":100.0,"DISHONOR_RATE":0.03,"HOUSING_PRICE":102.0,"HOUSEHOLD_DEBT":1497.0,
               "FACILITY_INVEST":94.5,"RETAIL_SALES":94.0,"CURRENT_ACCOUNT":774.7,"EMPLOYED":2633,"EMPLOYMENT_RATE":63.1,"OIL_PRICE":69.5,"COINCIDENT":101.5,"BSI_MANUF":88,"CONSTRUCTION_DONE":85.5,"SPI":94.5,"CONSTR_INVEST_GR":-4.6,"GFCF_GROWTH":-2.4,"SAVING_RATE":35.9,"INVEST_RATE":30.3,"TRADE_GNI":77.3,"MANUF_CAPACITY":107.0},
        2019: {"GDP_GROWTH":2.2,"UNEMPLOYMENT":3.8,"BASE_RATE":1.25,"CD_RATE":1.63,"CPI_GROWTH":0.4,"LEADING_INDEX":99.3,"GOVT_3Y":1.50,"GOVT_10Y":1.74,"CORP_AA":1.93,"CORP_BBB":4.52,"IPI":175.5,"EXPORT":542233,"IMPORT_AMT":503343,"USDKRW":1166,"M2":2694.0,"CSI":97.0,"KOSPI":2198,"IMPORT_PRICE":92.5,"DISHONOR_RATE":0.03,"HOUSING_PRICE":104.5,"HOUSEHOLD_DEBT":1573.0,
               "FACILITY_INVEST":89.0,"RETAIL_SALES":96.5,"CURRENT_ACCOUNT":597.0,"EMPLOYED":2660,"EMPLOYMENT_RATE":63.5,"OIL_PRICE":63.4,"COINCIDENT":100.0,"BSI_MANUF":82,"CONSTRUCTION_DONE":82.0,"SPI":97.0,"CONSTR_INVEST_GR":-3.1,"GFCF_GROWTH":-2.1,"SAVING_RATE":34.6,"INVEST_RATE":30.5,"TRADE_GNI":72.1,"MANUF_CAPACITY":102.8},
        2020: {"GDP_GROWTH":-0.7,"UNEMPLOYMENT":4.0,"BASE_RATE":0.50,"CD_RATE":0.76,"CPI_GROWTH":0.5,"LEADING_INDEX":97.0,"GOVT_3Y":0.98,"GOVT_10Y":1.52,"CORP_AA":2.03,"CORP_BBB":5.25,"IPI":170.0,"EXPORT":512498,"IMPORT_AMT":467633,"USDKRW":1180,"M2":3070.2,"CSI":90.0,"KOSPI":2873,"IMPORT_PRICE":85.0,"DISHONOR_RATE":0.02,"HOUSING_PRICE":110.0,"HOUSEHOLD_DEBT":1723.0,
               "FACILITY_INVEST":100.0,"RETAIL_SALES":100.0,"CURRENT_ACCOUNT":752.8,"EMPLOYED":2630,"EMPLOYMENT_RATE":62.5,"OIL_PRICE":42.3,"COINCIDENT":97.5,"BSI_MANUF":76,"CONSTRUCTION_DONE":79.0,"SPI":100.0,"CONSTR_INVEST_GR":-0.1,"GFCF_GROWTH":2.6,"SAVING_RATE":36.3,"INVEST_RATE":31.3,"TRADE_GNI":65.8,"MANUF_CAPACITY":100.0},
        2021: {"GDP_GROWTH":4.3,"UNEMPLOYMENT":3.7,"BASE_RATE":1.00,"CD_RATE":1.09,"CPI_GROWTH":2.5,"LEADING_INDEX":102.8,"GOVT_3Y":1.43,"GOVT_10Y":2.12,"CORP_AA":2.26,"CORP_BBB":5.64,"IPI":183.0,"EXPORT":644400,"IMPORT_AMT":615093,"USDKRW":1144,"M2":3415.8,"CSI":106.0,"KOSPI":2978,"IMPORT_PRICE":110.5,"DISHONOR_RATE":0.01,"HOUSING_PRICE":122.0,"HOUSEHOLD_DEBT":1853.0,
               "FACILITY_INVEST":108.5,"RETAIL_SALES":105.0,"CURRENT_ACCOUNT":883.0,"EMPLOYED":2672,"EMPLOYMENT_RATE":63.8,"OIL_PRICE":69.3,"COINCIDENT":103.0,"BSI_MANUF":96,"CONSTRUCTION_DONE":77.5,"SPI":104.5,"CONSTR_INVEST_GR":-1.5,"GFCF_GROWTH":3.1,"SAVING_RATE":35.8,"INVEST_RATE":31.6,"TRADE_GNI":74.5,"MANUF_CAPACITY":105.2},
        2022: {"GDP_GROWTH":2.6,"UNEMPLOYMENT":2.9,"BASE_RATE":3.25,"CD_RATE":3.77,"CPI_GROWTH":5.1,"LEADING_INDEX":99.2,"GOVT_3Y":3.14,"GOVT_10Y":3.60,"CORP_AA":4.25,"CORP_BBB":8.18,"IPI":186.5,"EXPORT":683585,"IMPORT_AMT":731370,"USDKRW":1292,"M2":3561.0,"CSI":95.0,"KOSPI":2237,"IMPORT_PRICE":140.2,"DISHONOR_RATE":0.02,"HOUSING_PRICE":128.0,"HOUSEHOLD_DEBT":1903.0,
               "FACILITY_INVEST":105.0,"RETAIL_SALES":107.5,"CURRENT_ACCOUNT":258.3,"EMPLOYED":2726,"EMPLOYMENT_RATE":64.5,"OIL_PRICE":97.0,"COINCIDENT":100.5,"BSI_MANUF":85,"CONSTRUCTION_DONE":76.0,"SPI":108.0,"CONSTR_INVEST_GR":-3.5,"GFCF_GROWTH":-0.7,"SAVING_RATE":34.5,"INVEST_RATE":31.8,"TRADE_GNI":85.2,"MANUF_CAPACITY":104.5},
        2023: {"GDP_GROWTH":1.4,"UNEMPLOYMENT":2.7,"BASE_RATE":3.50,"CD_RATE":3.75,"CPI_GROWTH":3.6,"LEADING_INDEX":98.8,"GOVT_3Y":3.55,"GOVT_10Y":3.78,"CORP_AA":4.40,"CORP_BBB":8.40,"IPI":183.0,"EXPORT":632744,"IMPORT_AMT":642756,"USDKRW":1305,"M2":3680.0,"CSI":96.5,"KOSPI":2655,"IMPORT_PRICE":120.0,"DISHONOR_RATE":0.03,"HOUSING_PRICE":118.0,"HOUSEHOLD_DEBT":1920.0,
               "FACILITY_INVEST":102.0,"RETAIL_SALES":106.0,"CURRENT_ACCOUNT":355.2,"EMPLOYED":2750,"EMPLOYMENT_RATE":65.0,"OIL_PRICE":82.5,"COINCIDENT":99.2,"BSI_MANUF":80,"CONSTRUCTION_DONE":72.0,"SPI":109.5,"CONSTR_INVEST_GR":-0.5,"GFCF_GROWTH":1.5,"SAVING_RATE":34.0,"INVEST_RATE":30.8,"TRADE_GNI":80.5,"MANUF_CAPACITY":101.0},
        2024: {"GDP_GROWTH":2.2,"UNEMPLOYMENT":2.8,"BASE_RATE":3.00,"CD_RATE":3.30,"CPI_GROWTH":2.3,"LEADING_INDEX":99.5,"GOVT_3Y":3.20,"GOVT_10Y":3.42,"CORP_AA":3.90,"CORP_BBB":7.50,"IPI":185.0,"EXPORT":660000,"IMPORT_AMT":650000,"USDKRW":1350,"M2":3800.0,"CSI":98.0,"KOSPI":2400,"IMPORT_PRICE":115.0,"DISHONOR_RATE":0.03,"HOUSING_PRICE":115.0,"HOUSEHOLD_DEBT":1950.0,
               "FACILITY_INVEST":103.5,"RETAIL_SALES":105.5,"CURRENT_ACCOUNT":380.0,"EMPLOYED":2760,"EMPLOYMENT_RATE":65.2,"OIL_PRICE":80.0,"COINCIDENT":99.5,"BSI_MANUF":82,"CONSTRUCTION_DONE":68.0,"SPI":110.0,"CONSTR_INVEST_GR":-3.3,"GFCF_GROWTH":0.8,"SAVING_RATE":33.5,"INVEST_RATE":30.0,"TRADE_GNI":82.0,"MANUF_CAPACITY":101.5},
        2025: {"GDP_GROWTH":1.8,"UNEMPLOYMENT":3.0,"BASE_RATE":2.75,"CD_RATE":3.00,"CPI_GROWTH":1.8,"LEADING_INDEX":99.8,"GOVT_3Y":2.80,"GOVT_10Y":3.10,"CORP_AA":3.50,"CORP_BBB":6.80,"IPI":184.0,"EXPORT":650000,"IMPORT_AMT":640000,"USDKRW":1380,"M2":3900.0,"CSI":99.0,"KOSPI":2500,"IMPORT_PRICE":110.0,"DISHONOR_RATE":0.03,"HOUSING_PRICE":112.0,"HOUSEHOLD_DEBT":1980.0,
               "FACILITY_INVEST":104.0,"RETAIL_SALES":106.0,"CURRENT_ACCOUNT":350.0,"EMPLOYED":2770,"EMPLOYMENT_RATE":65.5,"OIL_PRICE":75.0,"COINCIDENT":100.0,"BSI_MANUF":84,"CONSTRUCTION_DONE":65.0,"SPI":111.0,"CONSTR_INVEST_GR":-2.0,"GFCF_GROWTH":1.0,"SAVING_RATE":33.0,"INVEST_RATE":29.5,"TRADE_GNI":81.0,"MANUF_CAPACITY":101.0},
    }
    # fmt: on
    return pd.DataFrame(data).T.rename_axis("YEAR")


def fetch_and_cache(force=False, no_api=False):
    """ECOS에서 가져오거나 캐시 반환"""
    CACHE_DIR.mkdir(parents=True, exist_ok=True)
    
    if CACHE_FILE.exists() and not force:
        print(f"  캐시 로딩: {CACHE_FILE}")
        df = pd.read_csv(CACHE_FILE, index_col="YEAR")
        print(f"  변수: {len(df.columns)}개, 연도: {df.index.min()}~{df.index.max()}")
        return df
    
    if no_api:
        print("  API 없이 fallback 사용")
        df = _build_fallback()
        df.to_csv(CACHE_FILE)
        print(f"  캐시 저장: {CACHE_FILE} ({len(df.columns)}개 변수)")
        return df
    
    # ECOS API 수집
    print("  ECOS API에서 데이터 수집 중...")
    # TODO: API 실제 호출 구현 (config.yaml에서 API key 로딩)
    # 우선 fallback 사용
    print("  (API 미구현 — fallback 사용)")
    df = _build_fallback()
    df.to_csv(CACHE_FILE)
    print(f"  캐시 저장: {CACHE_FILE} ({len(df.columns)}개 변수)")
    return df


def load_macro_data(start_year=2000, end_year=2025) -> pd.DataFrame:
    """메인 파이프라인용 거시데이터 로딩"""
    if CACHE_FILE.exists():
        df = pd.read_csv(CACHE_FILE, index_col="YEAR")
    else:
        df = _build_fallback()
        CACHE_DIR.mkdir(parents=True, exist_ok=True)
        df.to_csv(CACHE_FILE)
    return df.loc[start_year:end_year]


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="ECOS 거시경제변수 수집기")
    parser.add_argument("--force", action="store_true", help="캐시 무시하고 재수집")
    parser.add_argument("--no-api", action="store_true", help="API 없이 fallback만 사용")
    args = parser.parse_args()
    
    print("=" * 60)
    print("  ECOS 거시경제변수 수집기")
    print("=" * 60)
    
    df = fetch_and_cache(force=args.force, no_api=args.no_api)
    
    print(f"\n  === 변수 목록 ({len(df.columns)}개) ===")
    for col in df.columns:
        vals = df[col].dropna()
        print(f"  {col:25s} | {vals.min():>12.2f} ~ {vals.max():>12.2f} | {len(vals)} obs")
    
    print(f"\n  === 최근 5년 ===")
    print(df.tail())
