#!/usr/bin/env python3
"""`.env` 완전성 및 config 로드 점검."""

from __future__ import annotations

import os
import re
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

ENV_FILE = ROOT / ".env"
CONFIG_FILE = ROOT / "config.py"

# config.py에서 읽는 환경 변수 키 (코드 기본값이 있는 항목)
CONFIG_ENV_KEYS = {
    "BITHUMB_API_URL",
    "BITHUMB_API_CANDLE_COUNT",
    "BITHUMB_MINUTE_INTERVALS",
    "HTS_API_RETRY_SLEEP_SEC",
    "SYMBOL",
    "COIN_NAME",
    "DAILY_INTERVAL_MIN",
    "ENTRY_INTERVAL",
    "TREND_INTERVAL_1H",
    "TREND_INTERVAL_1D",
    "ALL_INTERVALS",
    "DOWNLOAD_INTERVALS",
    "GENERAL_ANALYSIS_INTERVALS",
    "TIMING_INTERVALS",
    "TREND_INTERVALS",
    "INTERVAL_PREFIX",
    "BB_PERIOD",
    "BB_STD",
    "BB_MIN_WIDTH_PCT",
    "RSI_PERIOD",
    "DISPARITY_PERIODS",
    "DISPARITY_OVERBOUGHT",
    "DISPARITY_OVERSOLD",
    "MACD_FAST",
    "MACD_SLOW",
    "MACD_SIGNAL",
    "STOCH_K_PERIOD",
    "STOCH_D_PERIOD",
    "STOCH_SMOOTH_K",
    "STOCH_OVERSOLD",
    "STOCH_OVERBOUGHT",
    "TREND_RANGE_MA_GAP_PCT",
    "ALIGN_RSI_OVERSOLD",
    "ALIGN_RSI_OVERBOUGHT",
    "ALIGN_RSI_CONFLICT_TIMING_LOW",
    "ALIGN_RSI_CONFLICT_TIMING_HIGH",
    "ALIGN_RSI_CONFLICT_TREND_LOW",
    "ALIGN_RSI_CONFLICT_TREND_HIGH",
    "ALIGN_BB_POS_LOW",
    "ALIGN_BB_POS_HIGH",
    "DOWNLOAD_MONTHS",
    "DOWNLOAD_MONTHS_1M",
    "INCREMENTAL_OVERLAP_BARS",
    "DOWNLOAD_BACKFILL_EXTRA_BARS",
    "DOWNLOAD_MIN_INCREMENTAL_BARS",
    "DOWNLOAD_DAILY_EXTRA_DAYS",
    "CHART_LOOKBACK_DAYS",
    "DB_READ_LIMIT_DEFAULT",
    "DB_ROW_WARMUP_BARS",
    "DB_ROW_MIN_DAILY_BARS",
    "DB_ROW_DAILY_PADDING_DAYS",
    "DB_PATH",
    "GROUND_TRUTH_FILE",
    "GT_UNLIMITED_CHRONOLOGICAL_DAYS",
    "GT_MIN_SWING_PCT",
    "GT_PIVOT_ORDER",
    "GT_MIN_BARS_BETWEEN",
    "GT_MAX_ROUND_TRIPS",
    "GT_SELECTION_MODE",
    "GT_MIN_LEG_PCT",
    "GT_BUY_MIN_SWING_PCT",
    "GT_BUY_BB_MAX",
    "GT_BUY_MIN_BARS",
    "GT_MAX_BUYS_PER_LEG",
    "GT_MAX_SELLS_PER_LEG",
    "GT_SELL_SPLIT_GAP_PCT",
    "GT_MARKER_SIZE_MIN",
    "GT_MARKER_SIZE_MAX",
    "GT_INITIAL_CASH_KRW",
    "TRADING_FEE_RATE",
    "MONITOR_LOOP_SLEEP_SEC",
    "MONITOR_POOL_WORKERS",
    "MONITOR_DEFAULT_INTERVAL",
    "MONITOR_API_RETRIES",
    "MONITOR_API_BONG_COUNT",
    "MONITOR_SLEEP_AFTER_REQUEST_SEC",
    "MONITOR_SLEEP_RATE_LIMIT_SEC",
    "MONITOR_SLEEP_BETWEEN_CHUNKS_SEC",
    "MONITOR_API_CHUNK_BARS",
    "MONITOR_MA_WINDOWS",
    "MONITOR_NORM_WINDOW",
    "MONITOR_TELEGRAM_BATCH_SIZE",
    "GA_COL_PREFIX",
    "LOOKBACK_BARS",
    "CONTEXT_TAIL_ROWS",
    "GA_DEFAULT_TAIL_EXPORT",
    "GA_PATTERN_TOLERANCE_PCT",
    "GA_VP_BINS",
    "GA_VP_VALUE_AREA_PCT",
    "GA_HV_ROLLING_BARS",
    "GA_HV_PERCENTILE_WINDOW",
    "GA_HV_ANNUALIZE_SQRT",
    "GA_DIVERGENCE_LOOKBACK",
    "GA_SMA_PERIODS",
    "GA_EMA_SPANS",
    "GA_ATR_PERIOD",
    "GA_KELTNER_ATR_MULT",
    "GA_AO_FAST",
    "GA_AO_SLOW",
    "GA_LINREG_WINDOW",
    "GA_ADX_PERIOD",
    "GA_ADX_TREND_THRESHOLD",
    "GA_SUPERTREND_ATR_MULT",
    "GA_VOL_SPIKE_MULT",
    "GA_VOL_MA_WINDOW",
    "GA_CCI_PERIOD",
    "GA_WILLIAMS_PERIOD",
    "GA_ROC_PERIOD",
    "GA_MFI_PERIOD",
    "GA_CMF_PERIOD",
    "GA_DONCHIAN_PERIOD",
    "GA_BB_SQUEEZE_WINDOW",
    "GA_BB_SQUEEZE_QUANTILE",
    "GA_PIVOT_ORDER",
    "GA_PSAR_AF_START",
    "GA_PSAR_AF_STEP",
    "GA_PSAR_AF_MAX",
}

# 비어 있어도 되는 선택 항목 (현재는 모두 채움)
OPTIONAL_EMPTY = frozenset()


def parse_env_file(path: Path) -> dict[str, str]:
    """`.env` 키=값 파싱."""
    out: dict[str, str] = {}
    if not path.is_file():
        return out
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if "=" not in line:
            continue
        key, _, val = line.partition("=")
        out[key.strip()] = val.strip()
    return out


def main() -> int:
    errors: list[str] = []

    if not ENV_FILE.is_file():
        errors.append(f".env 없음: {ENV_FILE}")
        for e in errors:
            print(f"FAIL: {e}")
        return 1

    env_vars = parse_env_file(ENV_FILE)
    empty = [k for k, v in env_vars.items() if v == "" and k not in OPTIONAL_EMPTY]
    missing = sorted(CONFIG_ENV_KEYS - set(env_vars.keys()))
    extra = sorted(set(env_vars.keys()) - CONFIG_ENV_KEYS - {
        "BITHUMB_ACCESS_KEY",
        "BITHUMB_SECRET_KEY",
        "COIN_TELEGRAM_BOT_TOKEN",
        "COIN_TELEGRAM_CHAT_ID",
    })

    if empty:
        errors.append(f"빈 값: {', '.join(empty)}")
    if missing:
        errors.append(f"config 대비 .env 누락: {', '.join(missing)}")
    if extra:
        print(f"WARN: config 미사용 .env 키: {', '.join(extra)}")

    from deepcoin.env_loader import env_status, load_project_env

    loaded = load_project_env(override=True)
    if not loaded:
        errors.append("load_project_env: .env 로드 실패 (python-dotenv 확인)")

    import config  # noqa: E402

    checks = [
        ("SYMBOL", config.SYMBOL, env_vars.get("SYMBOL")),
        ("DB_PATH", config.DB_PATH, env_vars.get("DB_PATH")),
        ("BITHUMB_ACCESS_KEY", bool(config.BITHUMB_ACCESS_KEY), bool(env_vars.get("BITHUMB_ACCESS_KEY"))),
        ("LOOKBACK_BARS[3]", config.LOOKBACK_BARS.get(3), 120),
    ]
    for name, got, expected in checks:
        if got != expected and expected is not None:
            errors.append(f"config 불일치 {name}: got={got!r} expected={expected!r}")

    status = env_status()
    print("env_status:", status)
    print(f".env 키 수: {len(env_vars)} (config 필수 {len(CONFIG_ENV_KEYS)})")
    print(f"SYMBOL={config.SYMBOL} DB_PATH={config.DB_PATH}")
    print(f"BITHUMB_KEY set={bool(config.BITHUMB_ACCESS_KEY)} TELEGRAM set={bool(config.COIN_TELEGRAM_BOT_TOKEN)}")

    if errors:
        print("\n=== 점검 실패 ===")
        for e in errors:
            print(f"  - {e}")
        return 1

    print("\n=== 점검 통과: .env → config 로드 정상 ===")
    return 0


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