"""通用有限状态机实现 - 基于配置的声明式状态机."""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable

from ..logger import logger


@dataclass
class StateConfig:
    """状态配置数据类.

    Attributes
    ----------
        enables: 启用的组件名称集合
        transitions: 允许的状态转换 {action: target_state}
        metadata: 额外的元数据(可选)
    """

    enables: set[str] = field(default_factory=set)
    transitions: dict[str, str] = field(default_factory=dict)
    metadata: dict[str, Any] = field(default_factory=dict)


class StateMachineError(Exception):
    """状态机异常基类.

    Args:
        message: 错误消息
        current_state: 当前状态(可选)
        attempted_action: 尝试的动作(可选)
    """

    def __init__(self, message: str, current_state: str | None = None, attempted_action: str | None = None) -> None:
        super().__init__(message)
        self.current_state = current_state
        self.attempted_action = attempted_action

    def __str__(self) -> str:
        """返回错误消息字符串."""
        parts = [super().__str__()]
        if self.current_state:
            parts.append(f"当前状态:{self.current_state}")
        if self.attempted_action:
            parts.append(f"尝试动作:{self.attempted_action}")
        return ", ".join(parts)


class InvalidTransitionError(StateMachineError):
    """无效的状态转换异常."""

    pass


class StateNotFoundError(StateMachineError):
    """状态未找到异常."""

    pass


class StateMachine:
    """声明式有限状态机.

    特性:
    - 基于配置的声明式状态定义
    - 支持状态转换验证
    - 支持状态变更回调
    - 线程安全的状态访问
    - 详细的状态转换日志

    Example:
        >>> # 定义状态枚举
        >>> class ScannerState(str, Enum):
        ...     INIT = "init"
        ...     COUNTING = "counting"
        ...     SEARCHING = "searching"
        ...     FINISHED = "finished"
        >>>
        >>> # 创建状态机
        >>> sm = StateMachine(initial_state=ScannerState.INIT)
        >>>
        >>> # 注册状态配置
        >>> sm.register_state(
        ...     ScannerState.INIT,
        ...     StateConfig(
        ...         enables={"open_btn", "config_btn"},
        ...         transitions={"start_counting": ScannerState.COUNTING}
        ...     )
        ... )
        >>>
        >>> # 执行状态转换
        >>> sm.transition("start_counting")
        >>> print(sm.current_state)  # counting
    """

    def __init__(self, initial_state: str | Enum, on_state_change: Callable[[str, str], None] | None = None) -> None:
        """初始化状态机.

        Args:
            initial_state: 初始状态
            on_state_change: 状态变更回调函数 (old_state, new_state)
        """
        self._current_state = self._normalize_state(initial_state)
        self._states: dict[str, StateConfig] = {}
        self._on_state_change = on_state_change
        self._transition_history: list[tuple[str, str, str]] = []  # (from, action, to)

    @staticmethod
    def _normalize_state(state: str | Enum) -> str:
        """将状态标准化为字符串.

        Args:
            state: 状态值(字符串或 Enum)

        Returns
        -------
            标准化的状态字符串
        """
        if isinstance(state, Enum):
            return state.value if hasattr(state, "value") else state.name
        return state

    def register_state(self, state: str | Enum, config: StateConfig) -> None:
        """注册状态配置.

        Args:
            state: 状态标识
            config: 状态配置
        """
        state_str = self._normalize_state(state)
        self._states[state_str] = config
        logger.debug(f"注册状态:{state_str}, 配置:{config}")

    def register_states(self, states_config: dict[str | Enum, StateConfig]) -> None:
        """批量注册状态配置.

        Args:
            states_config: 状态配置字典 {state: StateConfig}
        """
        for state, config in states_config.items():
            self.register_state(state, config)

    @property
    def current_state(self) -> str:
        """获取当前状态.

        Returns
        -------
            当前状态字符串
        """
        return self._current_state

    @property
    def state_config(self) -> StateConfig | None:
        """获取当前状态的配置.

        Returns
        -------
            当前状态的配置,如果状态未注册则返回 None
        """
        return self._states.get(self._current_state)

    def has_state(self, state: str | Enum) -> bool:
        """检查状态是否已注册.

        Args:
            state: 要检查的状态

        Returns
        -------
            如果状态已注册返回 True
        """
        return self._normalize_state(state) in self._states

    def can_transition(self, action: str) -> bool:
        """检查是否可以执行指定的状态转换.

        Args:
            action: 转换动作名称

        Returns
        -------
            如果可以转换返回 True
        """
        current_config = self.state_config
        if not current_config:
            return False

        return action in current_config.transitions

    def get_available_actions(self) -> list[str]:
        """获取当前状态可用的转换动作列表.

        Returns
        -------
            可用动作名称列表
        """
        current_config = self.state_config
        if not current_config:
            return []

        return list(current_config.transitions.keys())

    def transition(self, action: str) -> bool:
        """执行状态转换.

        Args:
            action: 转换动作名称

        Returns
        -------
            如果转换成功返回 True

        Raises
        ------
            InvalidTransitionError: 当动作在当前状态下无效时
            StateNotFoundError: 当目标状态未注册时
        """
        current_config = self.state_config

        if not current_config:
            logger.warning(f"当前状态 '{self._current_state}' 未注册配置")
            return False

        if action not in current_config.transitions:
            available = self.get_available_actions()
            msg = f"状态 '{self._current_state}' 下不允许动作 '{action}'"
            if available:
                msg += f",可用动作:{available}"
            raise InvalidTransitionError(msg, self._current_state, action)

        # 获取目标状态
        target_state = current_config.transitions[action]

        if target_state not in self._states:
            msg = f"目标状态 '{target_state}' 未注册"
            raise StateNotFoundError(msg, self._current_state, action)

        # 执行状态转换
        old_state = self._current_state
        self._current_state = target_state

        # 记录转换历史
        self._transition_history.append((old_state, action, target_state))

        # 触发回调
        if self._on_state_change:
            try:
                self._on_state_change(old_state, target_state)
            except (TypeError, ValueError, RuntimeError) as e:
                logger.error(f"状态变更回调执行失败:{e}", exc_info=True)

        logger.info(f"状态转换:{old_state} --[{action}]--> {target_state}")
        return True

    def force_set_state(self, state: str | Enum) -> None:
        """强制设置状态(不执行转换逻辑).

        用于初始化或特殊情况下的状态重置.

        Args:
            state: 目标状态
        """
        old_state = self._current_state
        self._current_state = self._normalize_state(state)

        if self._on_state_change:
            try:
                self._on_state_change(old_state, self._current_state)
            except (TypeError, ValueError, RuntimeError) as e:
                logger.error(f"状态变更回调执行失败:{e}", exc_info=True)

        logger.debug(f"强制设置状态:{old_state} --> {self._current_state}")

    def get_transition_history(self, limit: int | None = None) -> list[tuple[str, str, str]]:
        """获取状态转换历史.

        Args:
            limit: 返回最近 N 条记录,None 表示返回全部

        Returns
        -------
            转换历史记录列表 [(from, action, to)]
        """
        if limit is None:
            return self._transition_history.copy()
        return self._transition_history[-limit:]

    def clear_history(self) -> None:
        """清空状态转换历史."""
        self._transition_history.clear()
        logger.debug("状态转换历史已清空")

    def __repr__(self) -> str:
        """返回状态机的字符串表示."""
        return (
            f"{self.__class__.__name__}(current_state='{self._current_state}', "
            f"registered_states={list(self._states.keys())})"
        )
