"""MARKET_SHARE_SIGNAL_V2 — 시장점유율 프록시 시그널 산출기.

실제 매출 기반 점유율 데이터가 없는 환경에서 3중 프록시를 사용한다:
  1. AvgTradeValue_20D_M — 20일 평균 거래대금(억 기준)  : 유동성/시장 영향력
  2. Frg_20D + Inst_20D  — 외인/기관 20일 누적 순매수   : 수급 강도
  3. Ret20D              — 20일 수익률                  : 상대 모멘텀

비-ETF 유니버스 내 백분위를 산출하여 GAINING/STABLE/LOSING을 결정한다.

백분위 계산:
  상위 33% → GAINING
  중간 34% → STABLE
  하위 33% → LOSING

ETF, 데이터 미수집 → NO_PEER_DATA

confidence: 항상 LOW (proxy 기반)
proxy_basis: "trade_volume_20d+flow+momentum"

참고: Revenue/시장점유율 실데이터 수집 후 HIGH confidence로 업그레이드 예정.
"""
from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any

ROOT = Path(__file__).resolve().parents[1]
DEFAULT_JSON = ROOT / "GatherTradingData.json"
DEFAULT_OUT = ROOT / "Temp" / "market_share_signal_v2.json"

_PERCENTILE_GAINING = 67.0   # 상위 33% (≥ 67번째 백분위)
_PERCENTILE_LOSING = 33.0    # 하위 33% (< 33번째 백분위)


def _load(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {}
    try:
        d = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    return d if isinstance(d, dict) else {}


def _rows(v: Any) -> list[dict[str, Any]]:
    if isinstance(v, list):
        return [x for x in v if isinstance(x, dict)]
    return []


def _f(v: Any, default: float | None = None) -> float | None:
    if v is None or v == "" or v == "N/A":
        return default
    try:
        return float(v)
    except (TypeError, ValueError):
        return default


import re as _re

# ETF 브랜드명 패턴 (이름 기반 1차 판별)
_ETF_NAME_RE = _re.compile(
    r"\b(KODEX|TIGER|KINDEX|ARIRANG|HANARO|KOSEF|TREX|SOL|FOCUS|ACE|TIMEFOLIO|PLUS)\b",
    _re.IGNORECASE,
)
# 6자리 중 5번째 자리 이후에 알파벳이 있는 ETF 티커 패턴 (예: 0117V0)
_ETF_TICKER_RE = _re.compile(r"^\d{4}[A-Z]\d")


def _is_etf(r: dict[str, Any]) -> bool:
    """ETF 여부 판별.

    판별 순서:
    1. Name에 ETF 브랜드명 포함 → ETF
    2. Ticker가 ETF 형식(영문자 포함 6자리) → ETF
    3. EPS / Forward_PE / PBR 모두 없을 때 → 재무 데이터 부재(ETF)
       단, 위 1·2가 모두 false면 비-ETF로 처리 (재무 데이터 미수집 주식 보호)
    """
    name = str(r.get("Name") or r.get("name") or "")
    ticker = str(r.get("Ticker") or r.get("ticker") or "")
    if _ETF_NAME_RE.search(name):
        return True
    if _ETF_TICKER_RE.match(ticker):
        return True
    # 재무 데이터가 있으면 비-ETF로 간주; 없어도 이름/티커 기반 판별이 false면 비-ETF 취급
    return False


def _composite_score(r: dict[str, Any]) -> float | None:
    """거래대금 + 수급 + 모멘텀 합산 점수 (정규화된 상대값)."""
    tv = _f(r.get("AvgTradeValue_20D_M"))
    frg = _f(r.get("Frg_20D"))
    inst = _f(r.get("Inst_20D"))
    ret20 = _f(r.get("Ret20D"))

    if tv is None:
        return None  # 점수 산출 불가

    # 각 요소 점수 (가중치)
    # 거래대금: 50% — 유동성/영향력의 핵심 지표
    tv_score = tv  # 억 단위, 이후 백분위 계산에서 정규화

    # 수급: 30% — 외인+기관 합산 순매수
    flow_score = 0.0
    if frg is not None:
        flow_score += frg * 0.5
    if inst is not None:
        flow_score += inst * 0.5

    # 모멘텀: 20% — 20일 수익률
    mom_score = ret20 if ret20 is not None else 0.0

    # 가중 합산을 위해 각 요소를 거래대금 단위로 스케일링
    # 거래대금이 가장 큰 절대값이므로 기준으로 사용
    composite = tv_score + (flow_score / 1e6 if flow_score != 0 else 0.0) + (mom_score * tv_score * 0.01)
    return composite


def _percentile_rank(value: float, sorted_values: list[float]) -> float:
    """sorted_values 내에서 value의 백분위 계산 (0~100)."""
    if not sorted_values:
        return 50.0
    n = len(sorted_values)
    rank = sum(1 for v in sorted_values if v <= value)
    return rank / n * 100.0


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--json", default=str(DEFAULT_JSON))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    args = ap.parse_args()

    json_path = Path(args.json) if Path(args.json).is_absolute() else ROOT / args.json
    out_path = Path(args.out) if Path(args.out).is_absolute() else ROOT / args.out

    payload = _load(json_path)
    data = payload.get("data") if isinstance(payload.get("data"), dict) else {}

    # data_feed 우선, universe 폴백
    df_list = _rows(data.get("data_feed")) or _rows(data.get("universe"))

    tickers_seen: set[str] = set()
    all_rows: list[dict[str, Any]] = []

    for r in df_list:
        ticker = str(r.get("Ticker") or r.get("ticker") or "")
        if not ticker or ticker in tickers_seen:
            continue
        tickers_seen.add(ticker)
        all_rows.append(r)

    # 비-ETF 유니버스만 백분위 산출
    non_etf_rows = [r for r in all_rows if not _is_etf(r)]
    non_etf_scores: dict[str, float] = {}

    for r in non_etf_rows:
        ticker = str(r.get("Ticker") or r.get("ticker") or "")
        score = _composite_score(r)
        if score is not None:
            non_etf_scores[ticker] = score

    sorted_scores = sorted(non_etf_scores.values())

    rows: list[dict[str, Any]] = []
    label_counts: dict[str, int] = {}

    for r in all_rows:
        ticker = str(r.get("Ticker") or r.get("ticker") or "")
        name = str(r.get("Name") or r.get("name") or "")

        if _is_etf(r):
            state = "NO_PEER_DATA"
            conf = "N/A"
            proxy_basis = "etf_excluded"
            pct_rank: float | None = None
            composite: float | None = None
        elif ticker not in non_etf_scores:
            state = "NO_PEER_DATA"
            conf = "N/A"
            proxy_basis = "trade_value_missing"
            pct_rank = None
            composite = None
        else:
            composite = non_etf_scores[ticker]
            pct_rank = _percentile_rank(composite, sorted_scores)
            if pct_rank >= _PERCENTILE_GAINING:
                state = "GAINING"
            elif pct_rank < _PERCENTILE_LOSING:
                state = "LOSING"
            else:
                state = "STABLE"
            conf = "LOW"
            proxy_basis = "trade_volume_20d+flow+momentum"

        entry = {
            "ticker": ticker,
            "name": name,
            "market_share_state": state,
            "confidence": conf,
            "proxy_basis": proxy_basis,
            "percentile_rank": round(pct_rank, 1) if pct_rank is not None else None,
            "composite_score": round(composite, 2) if composite is not None else None,
            "is_etf": _is_etf(r),
            "formula_id": "MARKET_SHARE_SIGNAL_V2",
        }
        rows.append(entry)
        label_counts[state] = label_counts.get(state, 0) + 1

    # 게이트: 비-ETF 중 GAINING/STABLE/LOSING이 고루 분포해야 신뢰성 있음
    non_etf_labeled = [r for r in rows if not r["is_etf"] and r["market_share_state"] != "NO_PEER_DATA"]
    unique_states = {r["market_share_state"] for r in non_etf_labeled}
    gate = "PASS" if len(unique_states) >= 2 else ("CAUTION" if non_etf_labeled else "FAIL")

    out = {
        "formula_id": "MARKET_SHARE_SIGNAL_V2",
        "gate": gate,
        "proxy_method": "trade_volume_20d+frg_inst_flow+ret20d_momentum",
        "confidence": "LOW",
        "non_etf_scored_count": len(non_etf_scores),
        "unique_states": sorted(unique_states),
        "label_counts": label_counts,
        "row_count": len(rows),
        "rows": rows,
    }
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding="utf-8")
    status = "MARKET_SHARE_SIGNAL_V2_OK" if gate != "FAIL" else "MARKET_SHARE_SIGNAL_V2_FAIL"
    print(
        f"MARKET_SHARE_SIGNAL_V2 gate={gate} rows={len(rows)} "
        f"non_etf_scored={len(non_etf_scores)} unique_states={sorted(unique_states)} "
        f"labels={label_counts}"
    )
    print(status)
    return 0


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