"""
TradingStateMachine - 状态机层

职责：
  1. 定义状态集合和迁移规则
  2. 验证状态迁移合法性（不允许非法跳转）
  3. 触发 GUI 动画回调
  4. 将迁移写入 ledger

底层依赖：
  - execution_state.py：持久化状态存储
  - ledger.py：迁移历史归档

状态定义（6个核心状态，映射到 pipeline.py 的执行状态）：

  UI_STATE        pipeline执行状态              说明
  ─────────────────────────────────────────────────────────────────────
  IDLE           CREATED (无活跃信号)        系统待机
  SIGNALING      CREATED → VALIDATING        策略计算中
  RISK_CHECK     VALIDATING → VALIDATED      风控仲裁中
  EXECUTING      VALIDATED → SENT            订单发送中
  CONFIRMED      ACKED / FILLED              订单确认/成交
  REJECTED       REJECTED / RECONCILED      订单被拒/超时/已平仓
  FAILED         TIMEOUT (重试耗尽)          执行失败

迁移规则（严格，不允许跳过中间状态）：
  IDLE → SIGNALING
  SIGNALING → RISK_CHECK
  RISK_CHECK → EXECUTING
  EXECUTING → CONFIRMED / REJECTED
  REJECTED → IDLE
  CONFIRMED → IDLE
  FAILED → IDLE

契约版本：1.0.0
"""
import threading
from datetime import datetime, timezone
from enum import Enum
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Protocol

# ─── 状态枚举 ────────────────────────────────────────────────────────────────

class TradingState(str, Enum):
    IDLE = "IDLE"
    SIGNALING = "SIGNALING"
    RISK_CHECK = "RISK_CHECK"
    EXECUTING = "EXECUTING"
    CONFIRMED = "CONFIRMED"
    REJECTED = "REJECTED"
    FAILED = "FAILED"

    def __str__(self) -> str:
        return self.value


# ─── 迁移规则表 ────────────────────────────────────────────────────────────

TRANSITIONS: Dict[TradingState, List[TradingState]] = {
    TradingState.IDLE:       [TradingState.SIGNALING],
    TradingState.SIGNALING:  [TradingState.RISK_CHECK, TradingState.IDLE],
    TradingState.RISK_CHECK: [TradingState.EXECUTING, TradingState.REJECTED, TradingState.IDLE],
    TradingState.EXECUTING:  [TradingState.CONFIRMED, TradingState.REJECTED, TradingState.FAILED],
    TradingState.CONFIRMED:  [TradingState.IDLE],
    TradingState.REJECTED:    [TradingState.IDLE],
    TradingState.FAILED:      [TradingState.IDLE],
}


# ─── GUI 动画映射 ───────────────────────────────────────────────────────────

STATE_ANIMATIONS: Dict[TradingState, Dict[str, Any]] = {
    TradingState.IDLE:       {"emoji": "🦞", "text": "待机中", "color": "gray", "anim": "sleep"},
    TradingState.SIGNALING:  {"emoji": "🦞", "text": "敲键盘分析中...", "color": "blue", "anim": "typing"},
    TradingState.RISK_CHECK: {"emoji": "🦞", "text": "看白板计算风险...", "color": "yellow", "anim": "calculating"},
    TradingState.EXECUTING:  {"emoji": "🦞", "text": "推送订单中...", "color": "blue", "anim": "shipping"},
    TradingState.CONFIRMED:  {"emoji": "🦞", "text": "✅ 订单确认", "color": "green", "anim": "success"},
    TradingState.REJECTED:   {"emoji": "🦞", "text": "⛔ 被风控拦截", "color": "orange", "anim": "blocked"},
    TradingState.FAILED:      {"emoji": "🦞", "text": "❌ 执行失败", "color": "red", "anim": "error"},
}


# ─── 异常定义 ────────────────────────────────────────────────────────────────

class InvalidStateTransitionError(Exception):
    def __init__(self, from_state: TradingState, to_state: TradingState):
        self.from_state = from_state
        self.to_state = to_state
        allowed = TRANSITIONS.get(from_state, [])
        super().__init__(
            f"非法迁移：不能从 {from_state.value} 跳转到 {to_state.value}。"
            f"允许的目标状态：{[s.value for s in allowed]}"
        )


# ─── 动画回调协议 ────────────────────────────────────────────────────────────

class AnimationCallback(Protocol):
    def on_state_change(self, from_state: TradingState, to_state: TradingState, metadata: dict) -> None:
        ...


class LoggingCallback(Protocol):
    def on_state_change(self, from_state: TradingState, to_state: TradingState, metadata: dict) -> None:
        ...


# ─── 核心状态机 ─────────────────────────────────────────────────────────────

class TradingStateMachine:
    """
    交易状态机

    使用方式：
        sm = TradingStateMachine(project_root=Path("."))

        # 注册回调
        sm.register_animation_callback(my_gui_handler)
        sm.register_ledger_callback(my_logger)

        # 执行迁移
        sm.transition(TradingState.SIGNALING, trace_id="sig_001")
        sm.transition(TradingState.RISK_CHECK, trace_id="sig_001")

        # 查询当前状态
        current = sm.get_current_state(trace_id)
    """

    SCHEMA_VERSION = "1.0.0"

    def __init__(
        self,
        project_root: Path,
        state_file: Path = None,
    ):
        self._root = project_root
        self._state_file = state_file or (project_root / "data" / "execution_state.json")

        # 当前活跃的 trace_id → 状态
        self._active_states: Dict[str, TradingState] = {}
        self._lock = threading.RLock()

        # 回调列表
        self._animation_callbacks: List[AnimationCallback] = []
        self._ledger_callbacks: List[LoggingCallback] = []

    # ── 回调注册 ──────────────────────────────────────────────────────────

    def register_animation_callback(self, cb: AnimationCallback) -> None:
        self._animation_callbacks.append(cb)

    def register_ledger_callback(self, cb: LoggingCallback) -> None:
        self._ledger_callbacks.append(cb)

    def _notify(self, from_state: TradingState, to_state: TradingState, metadata: dict) -> None:
        """通知所有回调"""
        for cb in self._animation_callbacks:
            try:
                cb.on_state_change(from_state, to_state, metadata)
            except Exception:
                pass
        for cb in self._ledger_callbacks:
            try:
                cb.on_state_change(from_state, to_state, metadata)
            except Exception:
                pass

    # ── 迁移验证 ──────────────────────────────────────────────────────────

    def _validate_transition(self, from_state: TradingState, to_state: TradingState) -> None:
        """验证迁移是否合法，不合法则抛出异常"""
        allowed = TRANSITIONS.get(from_state, [])
        if to_state not in allowed:
            raise InvalidStateTransitionError(from_state, to_state)

    # ── 状态查询 ──────────────────────────────────────────────────────────

    def get_current_state(self, trace_id: str) -> TradingState:
        with self._lock:
            return self._active_states.get(trace_id, TradingState.IDLE)

    def get_all_active(self) -> Dict[str, TradingState]:
        with self._lock:
            return dict(self._active_states)

    # ── 核心迁移方法 ──────────────────────────────────────────────────────

    def transition(
        self,
        to_state: TradingState,
        trace_id: str,
        reason: str = None,
        **metadata,
    ) -> TradingState:
        """
        执行状态迁移。

        参数：
            to_state:    目标状态（非枚举值会自动转换）
            trace_id:    信号追踪ID
            reason:      迁移原因（写入历史）
            **metadata:  附加信息（传给回调）

        返回：
            目标状态

        异常：
            InvalidStateTransitionError — 非法迁移
        """
        # 自动转换字符串
        if isinstance(to_state, str):
            to_state = TradingState(to_state.upper())

        with self._lock:
            from_state = self._active_states.get(trace_id, TradingState.IDLE)

            # IDLE → 任何状态都是允许的（首次迁移）
            if from_state == TradingState.IDLE:
                pass
            else:
                self._validate_transition(from_state, to_state)

            self._active_states[trace_id] = to_state

        # 组装元数据
        event = {
            "trace_id": trace_id,
            "from_state": from_state.value,
            "to_state": to_state.value,
            "reason": reason,
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "schema_version": self.SCHEMA_VERSION,
            **{k: v for k, v in metadata.items() if v is not None},
        }

        # 写入持久化（execution_state.py）
        try:
            from src.execution_state import transition_state as _persist
            _persist(self._state_file, trace_id, self._map_to_execution_state(to_state), reason=reason)
        except Exception:
            pass  # 持久化失败不阻断状态机

        # 触发回调（锁外通知，避免死锁）
        self._notify(from_state, to_state, event)

        return to_state

    def reset(self, trace_id: str) -> TradingState:
        """将指定 trace_id 重置为 IDLE"""
        return self.transition(TradingState.IDLE, trace_id=trace_id, reason="RESET")

    # ─── 辅助映射 ────────────────────────────────────────────────────────

    @staticmethod
    def _map_to_execution_state(state: TradingState) -> str:
        """将 UI 状态映射到 execution_state.py 的状态名"""
        mapping = {
            TradingState.IDLE: "CREATED",
            TradingState.SIGNALING: "CREATED",
            TradingState.RISK_CHECK: "VALIDATED",
            TradingState.EXECUTING: "SENT",
            TradingState.CONFIRMED: "FILLED",
            TradingState.REJECTED: "REJECTED",
            TradingState.FAILED: "TIMEOUT",
        }
        return mapping.get(state, "CREATED")

    @staticmethod
    def get_animation(state: TradingState) -> Dict[str, Any]:
        """获取状态的 GUI 动画配置"""
        if isinstance(state, str):
            state = TradingState(state.upper())
        return STATE_ANIMATIONS.get(state, STATE_ANIMATIONS[TradingState.IDLE])

    @staticmethod
    def is_final(state: TradingState) -> bool:
        """判断状态是否为终态"""
        return state in {TradingState.CONFIRMED, TradingState.REJECTED, TradingState.FAILED}


# ─── Ledger 写入回调 ─────────────────────────────────────────────────────────

class LedgerStateCallback:
    """
    将状态迁移写入 ledger 的回调实现。
    用法：sm.register_ledger_callback(LedgerStateCallback(project_root))
    """

    def __init__(self, project_root: Path):
        self._root = project_root

    def on_state_change(self, from_state: TradingState, to_state: TradingState, metadata: dict) -> None:
        try:
            from src.ledger import append_ledger_event
            append_ledger_event(
                self._root / "logs" / "decision_ledger.ndjson",
                category="state_transition",
                payload={
                    "type": "STATE_TRANSITION",
                    "schema_version": "1.0.0",
                    **metadata,
                },
            )
        except Exception:
            pass  # ledger 写入失败不阻断状态机


# ─── pipeline.py 集成钩子 ─────────────────────────────────────────────────────

def make_pipeline_callbacks(project_root: Path) -> tuple:
    """
    为 pipeline.py 创建状态机回调。
    返回：(animation_cb, ledger_cb)
    """
    ledger_cb = LedgerStateCallback(project_root)
    return ledger_cb, ledger_cb  # animation 和 ledger 共用同一实现
