"""Executor 基类。

参考 hummingbot strategy_v2/executors/executor_base.py：
- Controller 只产生"意图"（信号/配置），Executor 负责订单与仓位生命周期。
- 每个 executor 管理一个交易单元（一组网格层 / 一个趋势仓位）。
- 引擎每根已收盘 K 线调用 on_candle()，executor 内部状态机推进。

记账模型（回测与 paper 共用）：
- 开仓成交：free_wallet -= 保证金 + 手续费；保证金挂账到 executor。
- 平仓成交：free_wallet += 按比例释放的保证金 + 毛利 - 手续费。
- 权益 = free_wallet + Σ(保证金 + 未实现盈亏)。
"""
from __future__ import annotations

import logging
from typing import Optional

import pandas as pd

from ..models import CloseType, Side, TradeRecord

logger = logging.getLogger(__name__)


class ExecutionContext:
    """执行环境：费率与钱包记账。撮合细节由回测/实盘引擎提供。"""

    def __init__(self, fee_rate: float, wallet: float):
        self.fee_rate = fee_rate
        self.free_wallet = wallet
        self.start_wallet = wallet

    # ---- 记账原语（引擎调用） -----------------------------------------
    def apply_open_fill(self, ex: "ExecutorBase", price: float, amount: float,
                        ts: float) -> bool:
        notional = price * amount
        margin = notional / max(ex.leverage, 1e-9)
        fee = notional * self.fee_rate
        if margin + fee > self.free_wallet + 1e-9:
            # 交易所语义：保证金不足，订单被拒。该层不成交。
            return False
        ex.position.add(price, amount)
        ex.margin_reserved += margin
        ex.fees_paid += fee
        ex.entry_fills.append((ts, price, amount))
        self.free_wallet -= margin + fee
        return True

    def apply_close_fill(self, ex: "ExecutorBase", price: float, amount: float,
                         ts: float, close_type: CloseType, tag: str = "") -> None:
        amount = min(amount, ex.position.amount)
        if amount <= 0 or ex.position.entry_price <= 0:
            return
        entry_price = ex.position.entry_price
        frac = amount / ex.position.amount
        margin_release = ex.margin_reserved * frac
        gross = ex.position.reduce(price, amount)
        ex.margin_reserved -= margin_release
        fee = price * amount * self.fee_rate
        ex.fees_paid += fee
        net = gross - fee
        self.free_wallet += margin_release + net
        ex.trades.append(TradeRecord(
            pair=ex.pair, side=ex.side, entry_price=entry_price, exit_price=price,
            amount=amount, pnl_quote=net, fees_quote=fee, close_type=close_type,
            entry_ts=ex.created_ts, exit_ts=ts, tag=tag or ex.tag,
        ))
        if ex.position.amount <= 1e-12:
            ex.position.amount = 0.0
            ex.position.entry_price = 0.0
            ex.margin_reserved = 0.0
            ex.finish(ts, close_type)


class ExecutorBase:
    """交易执行单元基类。子类实现 on_candle 状态机。"""

    def __init__(self, pair: str, side: Side, leverage: float = 1.0, tag: str = ""):
        self.pair = pair
        self.side = side
        self.leverage = leverage
        self.tag = tag
        from ..models import Position
        self.position = Position(pair=pair, side=side, leverage=leverage)
        self.margin_reserved: float = 0.0
        self.is_active: bool = True
        self.close_type: Optional[CloseType] = None
        self.trades: list[TradeRecord] = []
        self.entry_fills: list[tuple[float, float, float]] = []
        self.fees_paid: float = 0.0
        self.created_ts: float = 0.0
        self.closed_ts: float = 0.0

    # ---- 引擎回调 ------------------------------------------------------
    def on_candle(self, candle: pd.Series, ctx: ExecutionContext) -> None:
        """每根已收盘 K 线调用一次。candle 含 open/high/low/close/ts。"""
        raise NotImplementedError

    def finish(self, ts: float, close_type: CloseType) -> None:
        if self.is_active:
            self.is_active = False
            self.close_type = close_type
            self.closed_ts = ts

    # ---- 统计 ----------------------------------------------------------
    @property
    def net_pnl(self) -> float:
        return sum(t.pnl_quote for t in self.trades)

    def unrealized_pnl(self, mark_price: float) -> float:
        return self.position.unrealized_pnl(mark_price)
