"""异步处理器模块"""
import queue
import threading
import time
import logging
from typing import Dict, List, Optional, Any
from .config import LogConfig

logger = logging.getLogger(__name__)


class AsyncHandler:
    """异步日志处理器
    
    使用后台线程异步处理日志，确保不阻塞业务代码
    """
    
    def __init__(self, config: LogConfig, transport, cache_manager):
        """初始化异步处理器
        
        Args:
            config: 日志配置
            transport: 传输层实例
            cache_manager: 缓存管理器实例
        """
        self.config = config
        self.transport = transport
        self.cache_manager = cache_manager
        
        # 创建队列
        self.queue = queue.Queue(maxsize=config.queue_maxsize)
        
        # 批量缓冲区
        self.buffer: List[Dict[str, Any]] = []
        self.last_send_time = time.time()
        
        # 运行标志
        self.running = True
        
        # 创建并启动后台线程
        self.worker_thread = threading.Thread(
            target=self._process_loop,
            daemon=True,
            name="LogAsyncHandler"
        )
        self.worker_thread.start()
        
        logger.info("异步处理器已启动")
    
    def enqueue(self, log_entry: Dict[str, Any]) -> bool:
        """将日志加入队列
        
        Args:
            log_entry: 日志条目
            
        Returns:
            是否成功加入队列
        """
        try:
            # 非阻塞方式放入队列
            self.queue.put_nowait(log_entry)
            return True
        except queue.Full:
            # 队列满时降级到本地缓存
            logger.warning("队列已满，降级到本地缓存")
            self.cache_manager.save_to_cache(log_entry)
            return False
    
    def _process_loop(self):
        """后台处理循环"""
        logger.info("后台处理线程开始运行")
        
        while self.running:
            try:
                # 从队列获取日志，设置超时以便定期检查批量发送
                try:
                    log_entry = self.queue.get(timeout=0.1)
                    self.buffer.append(log_entry)
                    self.queue.task_done()
                except queue.Empty:
                    pass
                
                # 检查是否需要批量发送
                current_time = time.time()
                time_elapsed = current_time - self.last_send_time
                
                should_send = (
                    len(self.buffer) >= self.config.batch_size or
                    (len(self.buffer) > 0 and time_elapsed >= self.config.batch_interval)
                )
                
                if should_send:
                    self._send_batch()
                
            except Exception as e:
                logger.error(f"处理循环异常: {e}", exc_info=True)
                time.sleep(1)  # 异常时短暂休眠
        
        # 退出前发送剩余日志
        if self.buffer:
            self._send_batch()
        
        logger.info("后台处理线程已停止")
    
    def _send_batch(self):
        """批量发送日志"""
        if not self.buffer:
            return
        
        batch = self.buffer[:]
        self.buffer.clear()
        self.last_send_time = time.time()
        
        try:
            # 尝试发送
            success = self.transport.send(batch)
            
            if success:
                logger.debug(f"成功发送 {len(batch)} 条日志")
            else:
                # 发送失败，保存到本地缓存
                logger.warning(f"发送失败，{len(batch)} 条日志已保存到本地缓存")
                for log_entry in batch:
                    self.cache_manager.save_to_cache(log_entry)
        
        except Exception as e:
            logger.error(f"发送批量日志异常: {e}", exc_info=True)
            # 异常时保存到本地缓存
            for log_entry in batch:
                self.cache_manager.save_to_cache(log_entry)
    
    def flush(self):
        """刷新缓冲区，发送所有待发送的日志"""
        if self.buffer:
            self._send_batch()
    
    def shutdown(self, timeout: float = 5.0):
        """关闭异步处理器
        
        Args:
            timeout: 等待超时时间（秒）
        """
        logger.info("正在关闭异步处理器...")
        
        # 设置停止标志
        self.running = False
        
        # 等待队列清空
        try:
            self.queue.join()
        except Exception as e:
            logger.error(f"等待队列清空时异常: {e}")
        
        # 等待线程结束
        self.worker_thread.join(timeout=timeout)
        
        if self.worker_thread.is_alive():
            logger.warning("后台线程未能在超时时间内结束")
        else:
            logger.info("异步处理器已关闭")
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息
        
        Returns:
            统计信息字典
        """
        return {
            "queue_size": self.queue.qsize(),
            "buffer_size": len(self.buffer),
            "is_running": self.running,
            "thread_alive": self.worker_thread.is_alive()
        }
