from abc import ABC, abstractmethod
from typing import Any, Dict, List
from xmpy.包_事件引擎 import 类_事件,类_事件引擎
from .模块_对象 import (
    类_行情数据, 类_成交数据, 类_订单数据, 类_持仓数据,
    类_账户数据, 类_合约数据, 类_日志数据, 类_报价数据,
    类_订阅请求, 类_订单请求, 类_撤单请求, 类_历史数据请求, 类_报价请求, 类_K线数据
)
from xmpy.包_交易核心.模块_常数 import 类_交易所
from .模块_事件类型 import (
    事件类型_行情, 事件类型_成交, 事件类型_订单,
    事件类型_持仓, 事件类型_账户, 事件类型_合约,
    事件类型_日志, 事件类型_报价
)


class 类_基础网关(ABC):
    """
    网关基类，用于对接不同交易系统的标准化接口

    实现网关时需要满足以下要求：
    1. 线程安全：所有方法需保证线程安全，对象间无可变共享状态
    2. 非阻塞：所有方法不得阻塞主线程
    3. 自动重连：网络中断后需自动尝试恢复连接
    """

    # 类属性定义
    默认名称: str = ""  # 网关默认名称
    默认配置: Dict[str, Any] = {}  # 连接所需配置模板
    支持交易所: List[类_交易所] = []  # 支持的交易所列表

    def __init__(self, 事件引擎: 类_事件引擎, 网关名称: str) -> None:
        """初始化网关实例"""
        self.事件引擎 = 事件引擎
        self.网关名称 = 网关名称

    def 触发事件(self, 事件类型: str, 事件数据: Any = None) -> None:
        """通用事件推送方法"""
        事件实例 = 类_事件(事件类型, 事件数据)
        self.事件引擎.放入事件(事件实例)

    def 推送行情(self, 行情实例: 类_行情数据) -> None:
        """处理行情数据推送"""
        # 推送全局行情事件
        self.触发事件(事件类型_行情, 行情实例)
        # 推送品种专属行情事件
        self.触发事件(f"{事件类型_行情}{行情实例.代码_交易所}", 行情实例)

    def 推送成交(self, 成交实例: 类_成交数据) -> None:
        """处理成交数据推送"""
        self.触发事件(事件类型_成交, 成交实例)
        self.触发事件(f"{事件类型_成交}{成交实例.代码_交易所}", 成交实例)

    def 推送订单(self, 订单实例: 类_订单数据) -> None:
        """处理订单状态更新"""
        self.触发事件(事件类型_订单, 订单实例)
        self.触发事件(f"{事件类型_订单}{订单实例.网关_订单编号}", 订单实例)

    def 推送持仓(self, 持仓实例: 类_持仓数据) -> None:
        """处理持仓数据更新"""
        self.触发事件(事件类型_持仓, 持仓实例)
        self.触发事件(f"{事件类型_持仓}{持仓实例.持仓_方向}", 持仓实例)

    def 推送账户(self, 账户实例: 类_账户数据) -> None:
        """处理账户资金变更"""
        self.触发事件(事件类型_账户, 账户实例)
        self.触发事件(f"{事件类型_账户}{账户实例.账户唯一标识}", 账户实例)

    def 推送报价(self, 报价实例: 类_报价数据) -> None:
        """处理报价数据更新"""
        self.触发事件(事件类型_报价, 报价实例)
        self.触发事件(f"{事件类型_报价}{报价实例.网关_报价编号}", 报价实例)

    def 记录日志(self, 日志内容: str) -> None:
        """生成日志事件"""
        日志实例 = 类_日志数据(消息内容=日志内容, 网关名称=self.网关名称)
        self.触发事件(事件类型_日志, 日志实例)

    def 推送合约(self, 合约实例: 类_合约数据) -> None:
        """处理合约信息更新"""
        self.触发事件(事件类型_合约, 合约实例)

    @abstractmethod
    def 连接(self, 连接配置: dict) -> None:
        """
        建立交易连接的核心方法

        实现要求：
        1. 完成服务器连接
        2. 连接成功后需查询并推送以下数据：
           - 合约信息：调用推送合约
           - 账户资金：调用推送账户
           - 持仓数据：调用推送持仓
           - 未完成订单：调用推送订单
           - 历史成交：调用推送成交
        3. 任一查询失败需记录错误日志
        """
        pass

    @abstractmethod
    def 断开连接(self) -> None:
        """关闭所有交易连接"""
        pass

    @abstractmethod
    def 订阅行情(self, 订阅请求: 类_订阅请求) -> None:
        """订阅指定合约的行情数据"""
        pass

    @abstractmethod
    def 发送委托(self, 订单请求: 类_订单请求) -> str:
        """
        委托下单处理

        实现要求：
        1. 根据请求创建订单数据对象
        2. 生成唯一订单编号（网关内唯一）
        3. 发送请求到交易服务器：
           - 发送成功：设置订单状态为"提交中"
           - 发送失败：设置订单状态为"已拒单"
        4. 返回格式：f"{网关名称}.{订单编号}"
        """
        pass

    @abstractmethod
    def 撤销订单(self, 撤单请求: 类_撤单请求) -> None:
        """撤销指定订单"""
        pass

    def 发送报价(self, 报价请求: 类_报价请求) -> str:
        """
        提交做市报价

        实现要求类似委托下单：
        1. 创建报价数据对象
        2. 生成唯一报价编号
        3. 处理服务器响应
        4. 返回格式：f"{网关名称}.{报价编号}"
        """
        return ""

    def 撤销报价(self, 撤单请求: 类_撤单请求) -> None:
        """撤销指定报价"""
        pass

    @abstractmethod
    def 查询账户(self) -> None:
        """主动查询账户资金信息"""
        pass

    @abstractmethod
    def 查询持仓(self) -> None:
        """主动查询持仓信息"""
        pass

    def 查询历史(self, 历史请求: 类_历史数据请求) -> List[类_K线数据]:
        """查询历史K线数据"""
        return []

    def 获取默认配置(self) -> Dict[str, Any]:
        """获取连接配置模板"""
        return self.默认配置.copy()  # 返回配置副本防止意外修改

    # 以下为需要子类维护的状态信息
    @property
    def 连接状态(self) -> bool:
        """返回当前网关连接状态（需子类实现）"""
        raise NotImplementedError

    @property
    def 交易状态(self) -> bool:
        """返回交易通道就绪状态（需子类实现）"""
        raise NotImplementedError