# server_context.py
# -*- coding: utf-8 -*-
import asyncio
from typing import Dict, List, Set, Deque, Optional, Tuple, Any
from collections import deque
from concurrent.futures import ThreadPoolExecutor
from fastapi import WebSocket

class ServerContext:
    """
    单例模式的服务器全局上下文
    用于统一管理状态、资源引用和客户端连接，解决 app_main.py 中 global 变量混乱的问题。
    """
    _instance = None
    _lock = asyncio.Lock()  # 异步锁，主要用于保护关键状态切换

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(ServerContext, cls).__new__(cls)
            cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if self._initialized:
            return
        
        self._initialized = True
        
        # ====== 1. WebSocket 客户端管理 ======
        self.ui_clients: Dict[int, WebSocket] = {}
        self.camera_viewers: Set[WebSocket] = set()
        self.imu_ws_clients: Set[WebSocket] = set()
        
        self.esp32_audio_ws: Optional[WebSocket] = None
        self.esp32_camera_ws: Optional[WebSocket] = None
        
        # ====== 2. 媒体数据缓冲 ======
        self.current_partial: str = ""
        self.recent_finals: List[str] = []
        self.last_frames: Deque[Tuple[float, bytes]] = deque(maxlen=10)
        
        # ====== 3. 业务状态标志 (State Flags) ======
        # 盲道导航状态
        self.navigation_active: bool = False
        # 过马路导航状态
        self.cross_street_active: bool = False
        # Omni 对话状态
        self.omni_conversation_active: bool = False
        self.omni_previous_nav_state: Optional[str] = None
        
        # YOLO 媒体流状态
        self.yolomedia_running: bool = False
        self.yolomedia_sending_frames: bool = False
        
        # ====== 4. 核心组件引用 (Resources) ======
        # 导航器实例
        self.blind_path_navigator = None
        self.cross_street_navigator = None
        self.indoor_navigator = None
        
        # 协调器
        self.orchestrator = None
        
        # 模型实例
        self.yolo_seg_model = None
        self.obstacle_detector = None
        self.indoor_seg_model = None
        
        # ====== 5. 异步处理资源 ======
        # 帧处理线程池
        self.frame_processing_executor = ThreadPoolExecutor(max_workers=3, thread_name_prefix="frame_proc")
        
        # 异步帧处理状态
        self.nav_processing_task: Optional[asyncio.Task] = None
        self.nav_last_result_image: Any = None
        self.nav_last_result_jpeg: Optional[bytes] = None
        self.nav_pending_frame: Any = None
        self.nav_processing_lock = asyncio.Lock()
        self.nav_task_start_time: float = 0.0

    def reset_navigation_state(self):
        """重置所有导航相关的状态标志"""
        self.navigation_active = False
        self.cross_street_active = False
        self.omni_conversation_active = False
        # 注意：这里不停止 orchestrator，只是重置标志位
        
    def add_ui_client(self, ws: WebSocket):
        self.ui_clients[id(ws)] = ws
        
    def remove_ui_client(self, ws: WebSocket):
        self.ui_clients.pop(id(ws), None)
        
    def get_ui_client_count(self) -> int:
        return len(self.ui_clients)

# 全局访问点
ctx = ServerContext()
