"""趋势仓位执行器：三重屏障（硬止损 / 移动止盈 / 时间限制）。

对应 hummingbot PositionExecutor + TripleBarrierConfig，
出场参数对齐 v5_d48 生产配置：硬止损 -5%，trailing 3%（激活线 5%，激活后才追踪）。
"""
from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import Optional

import pandas as pd

from ..models import CloseType, Side
from .base import ExecutionContext, ExecutorBase

logger = logging.getLogger(__name__)


@dataclass
class TripleBarrier:
    stop_loss_pct: float = 0.05                 # 硬止损（相对入场价，杠杆后价格口径）
    trailing_activation_pct: float = 0.05       # 浮盈达到 5% 激活
    trailing_distance_pct: float = 0.03         # 回撤 3% 触发
    time_limit_s: Optional[float] = None        # 可选时间止损


class PositionExecutor(ExecutorBase):
    """单边趋势仓：入场即成交（引擎负责），之后每根 K 线检查屏障。"""

    def __init__(self, pair: str, side: Side, barrier: TripleBarrier,
                 leverage: float = 2.0, tag: str = ""):
        super().__init__(pair=pair, side=side, leverage=leverage, tag=tag)
        self.barrier = barrier
        self._best_price: Optional[float] = None   # 多头最高价 / 空头最低价
        self._trailing_active = False

    def on_candle(self, candle: pd.Series, ctx: ExecutionContext) -> None:
        ts = float(candle["ts"])
        if self.created_ts == 0.0:
            self.created_ts = ts
        if self.position.amount <= 0:
            return

        entry = self.position.entry_price
        high, low, close = float(candle["high"]), float(candle["low"]), float(candle["close"])
        long = self.side is Side.BUY

        # 更新最优价与 trailing 激活状态（用 K 线极值近似）
        favorable = high if long else low
        if self._best_price is None:
            self._best_price = favorable
        elif long:
            self._best_price = max(self._best_price, high)
        else:
            self._best_price = min(self._best_price, low)

        gain = (self._best_price - entry) / entry if long else (entry - self._best_price) / entry
        if gain >= self.barrier.trailing_activation_pct:
            self._trailing_active = True

        # 1) 硬止损：K 线触及止损价 → 以止损价成交（跳空则按更差的开盘价）
        sl_price = entry * (1 - self.barrier.stop_loss_pct) if long \
            else entry * (1 + self.barrier.stop_loss_pct)
        sl_hit = (low <= sl_price) if long else (high >= sl_price)
        if sl_hit:
            fill = min(float(candle["open"]), sl_price) if long \
                else max(float(candle["open"]), sl_price)
            ctx.apply_close_fill(self, fill, self.position.amount, ts,
                                 CloseType.STOP_LOSS, tag="hard_sl")
            return

        # 2) 移动止盈：已激活且从最优价回撤超过 distance
        if self._trailing_active:
            trail_price = self._best_price * (1 - self.barrier.trailing_distance_pct) if long \
                else self._best_price * (1 + self.barrier.trailing_distance_pct)
            trail_hit = (low <= trail_price) if long else (high >= trail_price)
            if trail_hit:
                ctx.apply_close_fill(self, trail_price, self.position.amount, ts,
                                     CloseType.TRAILING_STOP, tag="trailing")
                return

        # 3) 时间止损
        if self.barrier.time_limit_s and ts - self.created_ts >= self.barrier.time_limit_s:
            ctx.apply_close_fill(self, close, self.position.amount, ts,
                                 CloseType.TIME_LIMIT, tag="time_limit")
