"""신호 → 1매수·1매도 레그 변환."""

from __future__ import annotations

from typing import Any

from deepcoin.techniques.base import TechniqueSignal


def signals_to_legs(
    signals: list[TechniqueSignal],
    min_leg_pct: float = 3.0,
) -> list[dict[str, Any]]:
    """시간순 신호를 1매수·1매도 레그로 짝짓는다.

    포지션 없을 때만 매수, 보유 중일 때만 매도를 인정한다.

    Args:
        signals: 시간순 TechniqueSignal 리스트.
        min_leg_pct: 최소 레그 수익률(%) 필터.

    Returns:
        GT legs와 동일 스키마의 레그 dict 리스트.
    """
    sorted_signals = sorted(signals, key=lambda s: s.bar_index)
    legs: list[dict[str, Any]] = []
    pending_buy: TechniqueSignal | None = None
    leg_id = 0

    for signal in sorted_signals:
        if signal.side == "buy":
            if pending_buy is None:
                pending_buy = signal
            elif signal.price < pending_buy.price:
                pending_buy = signal
            continue

        if signal.side != "sell" or pending_buy is None:
            continue

        leg_pct = (signal.price - pending_buy.price) / pending_buy.price * 100.0
        if leg_pct < min_leg_pct:
            continue

        leg_id += 1
        legs.append(
            {
                "leg_id": leg_id,
                "buy_datetime": pending_buy.datetime,
                "buy_price": round(pending_buy.price, 2),
                "buy_bar_index": pending_buy.bar_index,
                "sell_datetime": signal.datetime,
                "sell_price": round(signal.price, 2),
                "sell_bar_index": signal.bar_index,
                "leg_pct": round(leg_pct, 2),
                "bars_held": signal.bar_index - pending_buy.bar_index,
            }
        )
        pending_buy = None

    return legs


def summarize_legs(legs: list[dict[str, Any]]) -> dict[str, Any]:
    """레그 요약 통계를 계산한다."""
    if not legs:
        return {
            "leg_count": 0,
            "buy_count": 0,
            "sell_count": 0,
            "avg_leg_pct": 0.0,
            "median_leg_pct": 0.0,
            "max_leg_pct": 0.0,
            "min_leg_pct": 0.0,
            "avg_bars_held": 0.0,
        }

    pcts = [float(leg["leg_pct"]) for leg in legs]
    bars = [int(leg["bars_held"]) for leg in legs]
    pcts_sorted = sorted(pcts)
    mid = len(pcts_sorted) // 2
    median = (
        pcts_sorted[mid]
        if len(pcts_sorted) % 2 == 1
        else (pcts_sorted[mid - 1] + pcts_sorted[mid]) / 2
    )

    return {
        "leg_count": len(legs),
        "buy_count": len(legs),
        "sell_count": len(legs),
        "avg_leg_pct": round(sum(pcts) / len(pcts), 2),
        "median_leg_pct": round(median, 2),
        "max_leg_pct": round(max(pcts), 2),
        "min_leg_pct": round(min(pcts), 2),
        "avg_bars_held": round(sum(bars) / len(bars), 1),
    }


def legs_to_signal_dicts(legs: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """레그를 GT signals 형식으로 변환한다."""
    signals: list[dict[str, Any]] = []
    for leg in legs:
        signals.append(
            {
                "leg_id": leg["leg_id"],
                "side": "buy",
                "datetime": leg["buy_datetime"],
                "price": leg["buy_price"],
                "bar_index": leg["buy_bar_index"],
            }
        )
        signals.append(
            {
                "leg_id": leg["leg_id"],
                "side": "sell",
                "datetime": leg["sell_datetime"],
                "price": leg["sell_price"],
                "bar_index": leg["sell_bar_index"],
                "leg_pct": leg["leg_pct"],
            }
        )
    return signals
