"""
kis_trader/engine/orderbook_env.py — 호가필터 env 키 (전략 전용)
================================================================
글로벌 ``ORDERBOOK_*`` 임계값은 폐기. 실매·그리드·apply-best 는
``{SCALP|TAIL|MOMENTUM|BREAKOUT}_ORDERBOOK_*`` 만 사용.

코드 기본값 = DB 시드·웹 스키마 default 와 동일해야 함.
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional, Tuple

from kis_trader.utils.env import get_env_bool, get_env_float, get_env_from_db, get_env_int

# 임계값 기본 (하드코딩 금지 규칙: get_env_* 기본 인자로만 사용 · DB 시드와 동기)
OB_DEFAULT_FILTER_ENABLED = False  # 현행 실매 OFF 유지
OB_DEFAULT_MAX_SPREAD_PCT = 0.45
OB_DEFAULT_ENTRY_BID_LEVELS = 3
OB_DEFAULT_ENTRY_BID_DEPTH_MULT = 1.2
OB_DEFAULT_ENTRY_ASK_MAX_MULT = 3.0
OB_DEFAULT_MIN_BID_ASK_RATIO = 0.85
OB_DEFAULT_ASK_WALL_MAX_QTY = 5000

# 시드·UI 대상 전략 prefix (SHORT 오케스트레이터 → TAIL_* canonical)
OB_STRATEGY_PREFIXES: Tuple[str, ...] = ("SCALP", "TAIL", "MOMENTUM", "BREAKOUT")


def orderbook_strategy_prefix(strategy: str) -> str:
    s = (strategy or "").strip().upper()
    if s in ("BREAKOUT", "BO"):
        return "BREAKOUT"
    if s in ("MOMENTUM", "MOM"):
        return "MOMENTUM"
    if s in ("TAIL", "SHORT", "TAIL_CATCH"):
        return "TAIL"
    if s in ("SCALP", "SCALPING", "REVERSAL"):
        return "SCALP"
    return s


def _key(pfx: str, suffix: str) -> str:
    return f"{pfx}_ORDERBOOK_{suffix}"


def orderbook_filter_enabled(strategy: str) -> bool:
    """전략별 ON/OFF. 글로벌 ORDERBOOK_FILTER_ENABLED 폐기 → 기본 OFF."""
    pfx = orderbook_strategy_prefix(strategy)
    if not pfx or pfx == "ORDERBOOK":
        return False
    return get_env_bool(_key(pfx, "FILTER_ENABLED"), OB_DEFAULT_FILTER_ENABLED)


def get_ob_float(strategy: str, suffix: str, default: float) -> float:
    pfx = orderbook_strategy_prefix(strategy)
    if not pfx:
        return float(default)
    return float(get_env_float(_key(pfx, suffix), default))


def get_ob_int(strategy: str, suffix: str, default: int) -> int:
    pfx = orderbook_strategy_prefix(strategy)
    if not pfx:
        return int(default)
    return int(get_env_int(_key(pfx, suffix), default))


def load_orderbook_threshold_cfg(
    strategy: str,
    params: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """실매/백테 공통 임계값. params 의 ``_ob_*`` 가 있으면 덮어씀(파람서치)."""
    pfx = orderbook_strategy_prefix(strategy)
    cfg = {
        "max_spread_pct": get_ob_float(pfx, "MAX_SPREAD_PCT", OB_DEFAULT_MAX_SPREAD_PCT),
        "entry_bid_levels": get_ob_int(pfx, "ENTRY_BID_LEVELS", OB_DEFAULT_ENTRY_BID_LEVELS),
        "entry_bid_depth_mult": get_ob_float(
            pfx, "ENTRY_BID_DEPTH_MULT", OB_DEFAULT_ENTRY_BID_DEPTH_MULT,
        ),
        "entry_ask_max_mult": get_ob_float(
            pfx, "ENTRY_ASK_MAX_MULT", OB_DEFAULT_ENTRY_ASK_MAX_MULT,
        ),
        "min_bid_ask_ratio": get_ob_float(
            pfx, "MIN_BID_ASK_RATIO", OB_DEFAULT_MIN_BID_ASK_RATIO,
        ),
        "breakout_ask_wall_max_qty": get_ob_int(
            pfx, "ASK_WALL_MAX_QTY", OB_DEFAULT_ASK_WALL_MAX_QTY,
        ),
    }
    if params:
        _overrides = (
            ("_ob_max_spread_pct", "max_spread_pct"),
            ("_ob_min_bid_ask_ratio", "min_bid_ask_ratio"),
            ("_ob_ask_max_mult", "entry_ask_max_mult"),
            ("_ob_ask_wall_max_qty", "breakout_ask_wall_max_qty"),
            ("_ob_bid_depth_mult", "entry_bid_depth_mult"),
            ("_ob_bid_levels", "entry_bid_levels"),
        )
        for src_key, cfg_key in _overrides:
            ov = params.get(src_key)
            if ov is not None and str(ov).strip() != "":
                try:
                    cfg[cfg_key] = float(ov)
                except (TypeError, ValueError):
                    pass
    return cfg


def orderbook_params_to_env_patch(strategy: str, params: Dict[str, Any]) -> Dict[str, str]:
    """그리드/Optuna merged → 전략별 ORDERBOOK_* 패치 (값 있을 때만)."""
    pfx = orderbook_strategy_prefix(strategy)
    if not pfx:
        return {}
    out: Dict[str, str] = {}
    if "max_spread_pct" in params and params.get("max_spread_pct") not in (None, ""):
        out[_key(pfx, "MAX_SPREAD_PCT")] = str(float(params["max_spread_pct"]))
    if "min_bid_ask_ratio" in params and params.get("min_bid_ask_ratio") not in (None, ""):
        out[_key(pfx, "MIN_BID_ASK_RATIO")] = str(float(params["min_bid_ask_ratio"]))
    if "ask_max_mult" in params and params.get("ask_max_mult") not in (None, ""):
        out[_key(pfx, "ENTRY_ASK_MAX_MULT")] = str(float(params["ask_max_mult"]))
    if "ask_wall_max_qty" in params and params.get("ask_wall_max_qty") not in (None, ""):
        out[_key(pfx, "ASK_WALL_MAX_QTY")] = str(int(float(params["ask_wall_max_qty"])))
    if "bid_depth_mult" in params and params.get("bid_depth_mult") not in (None, ""):
        out[_key(pfx, "ENTRY_BID_DEPTH_MULT")] = str(float(params["bid_depth_mult"]))
    if "bid_levels" in params and params.get("bid_levels") not in (None, ""):
        out[_key(pfx, "ENTRY_BID_LEVELS")] = str(int(float(params["bid_levels"])))
    # 호가축이 섞인 apply 면 필터 ON (탐색 결과를 실매에 쓰려면 필요)
    if out and params.get("ob_filter_enabled") not in (None, ""):
        out[_key(pfx, "FILTER_ENABLED")] = (
            "true" if str(params.get("ob_filter_enabled")).lower() in ("1", "true", "yes", "on")
            else "false"
        )
    return out


def build_orderbook_seed_patch(
    *,
    filter_enabled: Optional[bool] = None,
    copy_global_if_empty: bool = True,
) -> Dict[str, str]:
    """전략별 기본값 시드. 빈 칸만 채움(이미 값 있으면 유지).

    copy_global_if_empty: 구 글로벌 ORDERBOOK_* 가 있으면 1회 이관.
    """
    fe = OB_DEFAULT_FILTER_ENABLED if filter_enabled is None else bool(filter_enabled)
    # 글로벌 → 전략 이관용 (폐기 전 잔존값)
    g_spread = str(get_env_from_db("ORDERBOOK_MAX_SPREAD_PCT", "") or "").strip()
    g_levels = str(get_env_from_db("ORDERBOOK_ENTRY_BID_LEVELS", "") or "").strip()
    g_depth = str(get_env_from_db("ORDERBOOK_ENTRY_BID_DEPTH_MULT", "") or "").strip()
    g_ask = str(get_env_from_db("ORDERBOOK_ENTRY_ASK_MAX_MULT", "") or "").strip()
    g_ratio = str(get_env_from_db("ORDERBOOK_MIN_BID_ASK_RATIO", "") or "").strip()
    g_wall = str(get_env_from_db("ORDERBOOK_BREAKOUT_ASK_WALL_MAX_QTY", "") or "").strip()
    g_filt = str(get_env_from_db("ORDERBOOK_FILTER_ENABLED", "") or "").strip()

    patch: Dict[str, str] = {}
    for pfx in OB_STRATEGY_PREFIXES:
        pairs: List[Tuple[str, str, str]] = [
            ("FILTER_ENABLED", "false" if not fe else "true", g_filt),
            ("MAX_SPREAD_PCT", str(OB_DEFAULT_MAX_SPREAD_PCT), g_spread),
            ("ENTRY_BID_LEVELS", str(OB_DEFAULT_ENTRY_BID_LEVELS), g_levels),
            ("ENTRY_BID_DEPTH_MULT", str(OB_DEFAULT_ENTRY_BID_DEPTH_MULT), g_depth),
            ("ENTRY_ASK_MAX_MULT", str(OB_DEFAULT_ENTRY_ASK_MAX_MULT), g_ask),
            ("MIN_BID_ASK_RATIO", str(OB_DEFAULT_MIN_BID_ASK_RATIO), g_ratio),
        ]
        if pfx == "BREAKOUT":
            pairs.append(("ASK_WALL_MAX_QTY", str(OB_DEFAULT_ASK_WALL_MAX_QTY), g_wall))
        for suf, default_s, glob_s in pairs:
            k = _key(pfx, suf)
            cur = str(get_env_from_db(k, "") or "").strip()
            if cur:
                continue
            if suf == "FILTER_ENABLED":
                # 시드 우선순위: 호출자 fe → (이관 시) 글로벌 → 코드 기본
                if filter_enabled is not None:
                    patch[k] = "true" if fe else "false"
                elif copy_global_if_empty and glob_s:
                    patch[k] = (
                        "true"
                        if glob_s.lower() in ("1", "true", "yes", "on")
                        else "false"
                    )
                else:
                    patch[k] = default_s
            elif copy_global_if_empty and glob_s:
                patch[k] = glob_s
            else:
                patch[k] = default_s
    return patch
