"""策略交易写入 trade_records 时的类型与复盘开仓类型标注."""
from __future__ import annotations

from typing import Optional

MONITOR_TYPE_TREND_PULLBACK = "趋势回调"
MONITOR_TYPE_ROLL = "顺势加仓"
ORDER_TYPE_MANUAL = "下单监控"
ORDER_TYPE_KEY = "关键位监控"

ENTRY_REASON_TREND_PULLBACK = "趋势回调"
ENTRY_REASON_ROLL = "顺势加仓"

JOURNAL_ORDER_TYPE_OPTIONS = (
    ORDER_TYPE_MANUAL,
    ORDER_TYPE_KEY,
    MONITOR_TYPE_TREND_PULLBACK,
    MONITOR_TYPE_ROLL,
)

STRATEGY_ENTRY_REASON_OPTIONS = (
    ENTRY_REASON_TREND_PULLBACK,
    ENTRY_REASON_ROLL,
)


def normalize_journal_order_type(raw: Optional[str]) -> str:
    s = (raw or "").strip()
    if s in JOURNAL_ORDER_TYPE_OPTIONS:
        return s
    if "关键位" in s:
        return ORDER_TYPE_KEY
    return ""


def order_type_from_monitor_type(
    monitor_type: Optional[str],
    key_signal_type: Optional[str] = None,
) -> str:
    del key_signal_type
    mt = (monitor_type or "").strip()
    if mt == MONITOR_TYPE_TREND_PULLBACK:
        return MONITOR_TYPE_TREND_PULLBACK
    if mt == MONITOR_TYPE_ROLL:
        return MONITOR_TYPE_ROLL
    if mt == ORDER_TYPE_KEY or "关键位" in mt:
        return ORDER_TYPE_KEY
    return ORDER_TYPE_MANUAL

# 趋势回调保本移交下单监控:order_monitors.key_signal_type / 平仓备注
TREND_HANDOFF_KEY_SIGNAL = ENTRY_REASON_TREND_PULLBACK
TREND_HANDOFF_TRADE_NOTE = "趋势回调计划"


def handoff_trade_miss_reason(miss_reason, row) -> Optional[str]:
    """趋势保本移交的监控单平仓:交易记录备注带来源."""
    if trend_plan_id_from_monitor_row(row) is None:
        return miss_reason
    base = (miss_reason or "").strip()
    if TREND_HANDOFF_TRADE_NOTE in base:
        return base or TREND_HANDOFF_TRADE_NOTE
    if base:
        return f"{TREND_HANDOFF_TRADE_NOTE};{base}"
    return TREND_HANDOFF_TRADE_NOTE


def trend_plan_id_from_monitor_row(row) -> Optional[int]:
    if row is None:
        return None
    try:
        keys = row.keys() if hasattr(row, "keys") else []
    except Exception:
        keys = []
    if "trend_plan_id" not in keys or row["trend_plan_id"] in (None, ""):
        return None
    try:
        tid = int(row["trend_plan_id"])
        return tid if tid > 0 else None
    except (TypeError, ValueError):
        return None


def order_had_roll_fills(conn, order_monitor_id) -> bool:
    try:
        oid = int(order_monitor_id)
    except (TypeError, ValueError):
        return False
    if oid <= 0:
        return False
    try:
        row = conn.execute(
            """SELECT 1 FROM roll_legs l
               INNER JOIN roll_groups g ON g.id = l.roll_group_id
               WHERE g.order_monitor_id=? AND l.status='filled'
               LIMIT 1""",
            (oid,),
        ).fetchone()
        return row is not None
    except Exception:
        return False


def _row_monitor_type(row, default_manual: str) -> str:
    if row is None:
        return default_manual
    try:
        keys = row.keys() if hasattr(row, "keys") else []
    except Exception:
        keys = []
    if "monitor_type" in keys:
        mt = (row["monitor_type"] or "").strip()
        if mt:
            return mt
    return default_manual


def _row_key_signal_type(row) -> str:
    if row is None:
        return ""
    try:
        keys = row.keys() if hasattr(row, "keys") else []
    except Exception:
        keys = []
    if "key_signal_type" not in keys:
        return ""
    return (row["key_signal_type"] or "").strip()


def order_monitor_source_type(row, *, default_manual: str = "下单监控") -> str:
    """展示/平仓记录:趋势保本移交单来源为「趋势回调」,非「下单监控」."""
    if trend_plan_id_from_monitor_row(row) is not None:
        return MONITOR_TYPE_TREND_PULLBACK
    mt = _row_monitor_type(row, default_manual)
    if mt != default_manual:
        return mt
    kst = _row_key_signal_type(row)
    if kst in (
        MONITOR_TYPE_TREND_PULLBACK,
        TREND_HANDOFF_KEY_SIGNAL,
        TREND_HANDOFF_TRADE_NOTE,
        ENTRY_REASON_TREND_PULLBACK,
    ):
        return MONITOR_TYPE_TREND_PULLBACK
    return mt


def apply_order_monitor_source_labels(item: dict, *, default_manual: str = "下单监控") -> dict:
    """实例页 / 中控 API:统一修正 order_monitors 展示用 monitor_type."""
    out = dict(item or {})
    out["monitor_type"] = order_monitor_source_type(out, default_manual=default_manual)
    return out


def trade_record_monitor_type(conn, order_row, *, default_manual: str = "下单监控") -> str:
    """平仓写入 trade_records 时:曾顺势加仓则标「顺势加仓」,否则沿用监控单来源类型."""
    oid = None
    try:
        keys = order_row.keys() if hasattr(order_row, "keys") else []
        if "id" in keys and order_row["id"] is not None:
            oid = int(order_row["id"])
    except Exception:
        oid = None
    if oid and order_had_roll_fills(conn, oid):
        return MONITOR_TYPE_ROLL
    return order_monitor_source_type(order_row, default_manual=default_manual)


def entry_reason_for_monitor_type(monitor_type: str | None) -> str:
    mt = (monitor_type or "").strip()
    if mt == MONITOR_TYPE_TREND_PULLBACK:
        return ENTRY_REASON_TREND_PULLBACK
    if mt == MONITOR_TYPE_ROLL:
        return ENTRY_REASON_ROLL
    return ""


def order_monitor_excluded_from_position_limit(conn, row) -> bool:
    """趋势回调不计入 MAX_ACTIVE_POSITIONS;顺势加仓在已有持仓上操作,单独放行."""
    return order_monitor_source_type(row) == MONITOR_TYPE_TREND_PULLBACK


def count_position_limit_active_monitors(conn) -> int:
    """计入仓位上限冻结的活跃监控数(不含趋势回调,顺势加仓)."""
    try:
        rows = conn.execute("SELECT * FROM order_monitors WHERE status='active'").fetchall()
    except Exception:
        return 0
    n = 0
    for row in rows:
        if not order_monitor_excluded_from_position_limit(conn, row):
            n += 1
    return n
