"""
kis_trader.execution.orderbook_sell — 익절(수익) 매도 시 호가 잔량 방어
======================================================================
손절·긴급 청산은 OrderManager 가 시장가로 처리한다.
수익 구간 매도만 매수 1~N호가 잔량을 확인한 뒤 매수 1호가 지정가를 권장한다.
"""
from __future__ import annotations

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

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

logger = logging.getLogger("kis_trader.orderbook_sell")


_URGENT_SELL_TOKENS = (
    "손절", "손실컷", "금액손실", "stop_loss", "stop loss",
    "장마감", "eod", "emergency", "긴급",
)


def is_urgent_market_sell_reason(reason: str) -> bool:
    """손절·장마감·긴급 — 시장가·만료 즉시 재주문 대상."""
    r = (reason or "").strip().lower()
    if not r:
        return False
    return any(t in r for t in _URGENT_SELL_TOKENS)


def is_profit_take_sell_reason(reason: str) -> bool:
    """수익·본전 방어 청산(지정가 후보). 손절·장마감·금액손실컷은 False."""
    r = (reason or "").strip().lower()
    if not r:
        return False
    if any(t in r for t in _URGENT_SELL_TOKENS):
        return False
    profit_tokens = (
        "익절", "어깨", "트레일", "본절", "take_profit", "trailing", "profit",
    )
    return any(t in r for t in profit_tokens)


def parse_kis_bid_levels(raw: Optional[Dict[str, Any]], levels: int = 5) -> List[Dict[str, Any]]:
    """KIS 호가 API output → [{'price': int, 'bid_qty': int}, ...] (비싼 매수호가 순)."""
    if not raw or not isinstance(raw, dict):
        return []
    out: List[Dict[str, Any]] = []
    for i in range(1, max(1, levels) + 1):
        px_raw = raw.get(f"bidp{i}") or raw.get(f"BIDP{i}")
        qty_raw = raw.get(f"bidp_rsqn{i}") or raw.get(f"BIDP_RSQN{i}")
        if px_raw in (None, "", "0"):
            continue
        try:
            price = int(abs(float(str(px_raw).replace(",", ""))))
        except (TypeError, ValueError):
            continue
        if price <= 0:
            continue
        try:
            bid_qty = int(abs(float(str(qty_raw or "0").replace(",", ""))))
        except (TypeError, ValueError):
            bid_qty = 0
        out.append({"price": price, "bid_qty": bid_qty})
    return out


def resolve_orderbook_raw(
    code: str,
    *,
    ws_get=None,
    rest_client=None,
    max_age_sec: float = 3.0,
) -> Tuple[Optional[Dict[str, Any]], str]:
    """
    호가 조회 — 키움 WS 캐시 우선, 없으면 KIS REST.
    Returns: (raw_dict, source_tag)  source_tag: kiwoom_ws | kis_rest | none
    """
    c = str(code or "").strip()
    if ws_get and c:
        try:
            raw = ws_get(c, max_age_sec=max_age_sec)
        except TypeError:
            try:
                raw = ws_get(c)
            except Exception:
                raw = None
        except Exception:
            raw = None
        if raw:
            return raw, "kiwoom_ws"
    if rest_client and c:
        try:
            raw = rest_client.get_orderbook(c)
            if raw:
                return raw, "kis_rest"
        except Exception:
            pass
    return None, "none"


def evaluate_take_profit_limit_sell(
    holding_qty: int,
    orderbook_raw: Optional[Dict[str, Any]],
) -> Tuple[bool, int, str]:
    """
  익절용 지정가 매도 가능 여부.
  Returns: (실행여부, 지정가, 메시지)
    """
    qty = int(holding_qty or 0)
    if qty <= 0:
        return False, 0, "qty<=0"

    levels = get_env_int("SELL_ORDERBOOK_BID_LEVELS", 2)
    depth_mult = get_env_float("SELL_ORDERBOOK_DEPTH_MULT", 1.5)
    bids = parse_kis_bid_levels(orderbook_raw, levels=max(levels, 2))
    if len(bids) < 1:
        return False, 0, "no_bid_data"

    top_n = bids[:levels]
    total_bid = sum(int(b.get("bid_qty", 0) or 0) for b in top_n)
    best_price = int(top_n[0]["price"])
    need = int(qty * depth_mult)
    if total_bid < need:
        logger.info(
            "호가 얇음 — 익절 대기: 매수1~%d호가 합 %d주 < 필요 %d주 (보유 %d)",
            levels, total_bid, need, qty,
        )
        return False, 0, "orderbook_thin"

    return True, best_price, "TAKE_PROFIT_BEST_LIMIT"
