/**
 * WebSocket 消息处理器
 * 处理所有来自 WebSocket 的消息事件
 * 
 * 重构说明：
 * - 直接使用 zustand store 替代 IMessageStateManager
 * - 移除了 SubscriptionManager 调用，Zustand 的 set() 会自动触发组件重渲染
 */

import type {
  WSChatMessage,
  WSGroupChatMessage,
  WSReadMessage,
  WSGroupReadMessage,
  WSRecallMessage,
  WSGroupRecallMessage,
  WSGroupTypingMessage,
  WSGroupNoticeMessage,
} from '@/services/core';
import { wsService, GroupNoticeType } from '@/services/core';
import { eventBus } from '@/core/events/EventBus';
import { messageRepository } from '@/database';
import type { MessageResponse, ConversationResponse } from '../../../types/dto';
import type {
  IWSMessageHandler,
  IMessageDeduplication,
  IUserCacheService,
  HandleNewMessageOptions,
} from '../types';
import { MAX_FLUSH_ITERATIONS } from '../constants';
import { useMessageStore, normalizeConversationId, mergeMessagesById } from '../store';

export class WSMessageHandler implements IWSMessageHandler {
  private deduplication: IMessageDeduplication;
  private userCacheService: IUserCacheService;
  private getCurrentUserId: () => string | null;
  private markAsReadCallback: (conversationId: string, seq: number) => Promise<void>;
  private fetchConversationsCallback: (forceRefresh: boolean, source: string) => Promise<void>;
  private fetchUnreadCountCallback: () => Promise<void>;
  private fetchMessagesCallback: (conversationId: string) => Promise<void>;

  private sseUnsubscribe: (() => void) | null = null;
  private isBootstrapping: boolean = false;
  private lastReconnectSyncAt: number = 0;

  // 初始化阶段缓冲来自 SSE 的消息事件
  private bufferedChatMessages: Array<(WSChatMessage | WSGroupChatMessage) & { _isAck?: boolean }> = [];
  private bufferedReadReceipts: Array<WSReadMessage | WSGroupReadMessage> = [];

  constructor(
    deduplication: IMessageDeduplication,
    userCacheService: IUserCacheService,
    getCurrentUserId: () => string | null,
    callbacks: {
      markAsRead: (conversationId: string, seq: number) => Promise<void>;
      fetchConversations: (forceRefresh: boolean, source: string) => Promise<void>;
      fetchUnreadCount: () => Promise<void>;
      fetchMessages: (conversationId: string) => Promise<void>;
    }
  ) {
    this.deduplication = deduplication;
    this.userCacheService = userCacheService;
    this.getCurrentUserId = getCurrentUserId;
    this.markAsReadCallback = callbacks.markAsRead;
    this.fetchConversationsCallback = callbacks.fetchConversations;
    this.fetchUnreadCountCallback = callbacks.fetchUnreadCount;
    this.fetchMessagesCallback = callbacks.fetchMessages;
  }

  /**
   * 初始化 SSE 监听器
   */
  connect(): void {
    if (this.sseUnsubscribe) {
      this.sseUnsubscribe();
    }

    wsService.on('chat', (message: WSChatMessage) => {
      if (!useMessageStore.getState().isInitialized || this.isBootstrapping) {
        this.bufferedChatMessages.push(message);
        return;
      }
      this.handleNewMessage(message);
    });

    wsService.on('group_message', (message: WSGroupChatMessage) => {
      if (!useMessageStore.getState().isInitialized || this.isBootstrapping) {
        this.bufferedChatMessages.push(message);
        return;
      }
      this.handleNewMessage(message);
    });

    wsService.on('read', (message: WSReadMessage) => {
      if (!useMessageStore.getState().isInitialized || this.isBootstrapping) {
        this.bufferedReadReceipts.push(message);
        return;
      }
      this.handleReadReceipt(message);
    });

    // 监听群聊已读回执
    wsService.on('group_read', (message: WSGroupReadMessage) => {
      if (!useMessageStore.getState().isInitialized || this.isBootstrapping) {
        this.bufferedReadReceipts.push(message);
        return;
      }
      this.handleGroupReadReceipt(message);
    });

    // 监听私聊消息撤回
    wsService.on('recall', (message: WSRecallMessage) => {
      this.handleRecallMessage(message);
    });

    // 监听群聊消息撤回
    wsService.on('group_recall', (message: WSGroupRecallMessage) => {
      this.handleGroupRecallMessage(message);
    });

    // 监听群聊输入状态
    wsService.on('group_typing', (message: WSGroupTypingMessage) => {
      this.handleGroupTyping(message);
    });

    // 监听群通知
    wsService.on('group_notice', (message: WSGroupNoticeMessage) => {
      this.handleGroupNotice(message);
    });

    // 监听连接状态
    wsService.onConnect(() => {
      useMessageStore.getState().setSSEConnected(true);

      // 冷启动/重连兜底
      const now = Date.now();
      if (now - this.lastReconnectSyncAt > 1500) {
        this.lastReconnectSyncAt = now;
        const activeConversation = useMessageStore.getState().getActiveConversation();
        
        if (!activeConversation) {
          this.fetchConversationsCallback(true, 'sse-reconnect').catch(error => {
            console.error('[WSMessageHandler] 连接后同步会话失败:', error);
          });
        } else {
          this.fetchUnreadCountCallback().catch(error => {
            console.error('[WSMessageHandler] 连接后同步未读数失败:', error);
          });
        }
        
        if (activeConversation) {
          this.fetchMessagesCallback(activeConversation).catch(error => {
            console.error('[WSMessageHandler] 连接后同步当前会话消息失败:', error);
          });
        }
      }
    });

    wsService.onDisconnect(() => {
      useMessageStore.getState().setSSEConnected(false);
    });
  }

  /**
   * 断开 SSE 连接
   */
  disconnect(): void {
    if (this.sseUnsubscribe) {
      this.sseUnsubscribe();
      this.sseUnsubscribe = null;
    }
  }

  /**
   * 检查是否已连接
   */
  isConnected(): boolean {
    return useMessageStore.getState().isConnected();
  }

  /**
   * 设置启动状态
   */
  setBootstrapping(value: boolean): void {
    this.isBootstrapping = value;
  }

  /**
   * 初始化完成后，处理缓冲的 SSE 事件
   */
  async flushBufferedSSEEvents(): Promise<void> {
    for (let i = 0; i < MAX_FLUSH_ITERATIONS; i++) {
      const hasBuffered = this.bufferedChatMessages.length > 0 || this.bufferedReadReceipts.length > 0;
      if (!hasBuffered) return;

      const chatEvents = this.bufferedChatMessages;
      const readEvents = this.bufferedReadReceipts;
      this.bufferedChatMessages = [];
      this.bufferedReadReceipts = [];

      // 处理消息
      for (const m of chatEvents) {
        await this.handleNewMessage(m, {
          suppressUnreadIncrement: true,
          suppressVibration: true,
          suppressConversationUpdates: true,
          suppressAutoMarkAsRead: true,
        });
      }

      // 处理已读回执
      for (const r of readEvents) {
        if (r.type === 'read') {
          this.handleReadReceipt(r);
        } else {
          this.handleGroupReadReceipt(r as WSGroupReadMessage);
        }
      }

      // 使用服务器权威刷新
      await this.fetchConversationsCallback(true, 'sse-buffer-flush');
      await this.fetchUnreadCountCallback();
    }
  }

  /**
   * 处理新消息（SSE推送）
   */
  async handleNewMessage(
    message: (WSChatMessage | WSGroupChatMessage) & { _isAck?: boolean },
    options?: HandleNewMessageOptions
  ): Promise<void> {
    const store = useMessageStore.getState();
    const { conversation_id, id, sender_id, seq, segments, created_at, _isAck } = message;
    const normalizedConversationId = normalizeConversationId(conversation_id);
    const currentUserId = this.getCurrentUserId();
    const suppressUnreadIncrement = options?.suppressUnreadIncrement ?? false;
    const suppressVibration = options?.suppressVibration ?? false;
    const suppressConversationUpdates = options?.suppressConversationUpdates ?? false;
    const suppressAutoMarkAsRead = options?.suppressAutoMarkAsRead ?? false;

    // 消息去重检查
    if (this.deduplication.isMessageProcessed(id)) {
      return;
    }
    this.deduplication.markMessageAsProcessed(id);

    // 对于群聊消息，获取发送者信息
    if (message.type === 'group_message' && sender_id && sender_id !== currentUserId && sender_id !== '10000') {
      this.userCacheService.getSenderInfo(sender_id).then(user => {
        if (user) {
          const currentMessages = store.getMessages(normalizedConversationId);
          if (currentMessages) {
            const updatedMessages = currentMessages.map(m =>
              m.id === id ? { ...m, sender: user } : m
            );
            store.setMessages(normalizedConversationId, updatedMessages);
          }
        }
      }).catch(error => {
        console.error('[WSMessageHandler] 获取发送者信息失败:', { userId: sender_id, error });
      });
    }

    // 构造消息对象
    const newMessage: MessageResponse = {
      id,
      conversation_id: normalizedConversationId,
      sender_id,
      seq,
      segments: segments || [],
      created_at,
      status: 'normal',
    };

    // 立即更新内存中的消息列表
    const existingMessages = store.getMessages(normalizedConversationId);
    const messageExists = existingMessages.some(m => String(m.id) === String(id));

    if (!messageExists) {
      const updatedMessages = mergeMessagesById(existingMessages, [newMessage]);
      store.setMessages(normalizedConversationId, updatedMessages);
    }

    // 更新会话信息
    if (!suppressConversationUpdates) {
      this.updateConversationWithNewMessage(normalizedConversationId, newMessage, created_at);
    }

    // 更新未读数
    const isCurrentUserMessage = sender_id === currentUserId;
    const isActiveConversation = normalizedConversationId === store.getActiveConversation();

    const shouldIncrementUnread =
      !suppressUnreadIncrement &&
      !isCurrentUserMessage &&
      !isActiveConversation &&
      !!currentUserId &&
      !_isAck;

    if (shouldIncrementUnread) {
      if (!suppressVibration) {
        const vibrationType = message.type === 'group_message' ? 'group_message' : 'message';
        eventBus.emit({ type: 'VIBRATE', payload: { type: vibrationType } });
      }
      this.incrementUnreadCount(normalizedConversationId);
    }

    // 如果是当前活动会话，自动标记已读
    if (isActiveConversation && !isCurrentUserMessage && !suppressAutoMarkAsRead) {
      this.markAsReadCallback(normalizedConversationId, seq).catch(() => {});
    }

    // 异步保存到本地数据库
    const textContent = segments?.filter((s: any) => s.type === 'text').map((s: any) => s.data?.text || '').join('') || '';
    messageRepository.saveMessage({
      id,
      conversationId: normalizedConversationId,
      senderId: sender_id || '',
      content: textContent,
      type: segments?.find((s: any) => s.type === 'image') ? 'image' : 'text',
      isRead: isActiveConversation,
      createdAt: new Date(created_at).toISOString(),
      seq,
      status: 'normal',
      segments,
    }).catch(error => {
      console.error('[WSMessageHandler] 保存消息到本地失败:', error);
    });
  }

  /**
   * 处理私聊已读回执
   */
  handleReadReceipt(message: WSReadMessage): void {
    // 可以在这里处理对方已读的状态更新
  }

  /**
   * 处理群聊已读回执
   */
  handleGroupReadReceipt(message: WSGroupReadMessage): void {
    // 群聊已读回执处理
  }

  /**
   * 处理私聊消息撤回
   */
  handleRecallMessage(message: WSRecallMessage): void {
    const { conversation_id, message_id } = message;
    const normalizedConversationId = normalizeConversationId(conversation_id);

    this.markMessageAsRecalled(normalizedConversationId, message_id);
    this.syncConversationLastMessageOnRecall(normalizedConversationId, message_id);

    messageRepository.updateStatus(message_id, 'recalled', true).catch(error => {
      console.error('[WSMessageHandler] 更新本地消息撤回状态失败:', error);
    });
  }

  /**
   * 处理群聊消息撤回
   */
  handleGroupRecallMessage(message: WSGroupRecallMessage): void {
    const { conversation_id, message_id } = message;
    const normalizedConversationId = normalizeConversationId(conversation_id);

    this.markMessageAsRecalled(normalizedConversationId, message_id);
    this.syncConversationLastMessageOnRecall(normalizedConversationId, message_id);

    messageRepository.updateStatus(message_id, 'recalled', true).catch(error => {
      console.error('[WSMessageHandler] 更新本地消息撤回状态失败:', error);
    });
  }

  /**
   * 处理群聊输入状态
   */
  handleGroupTyping(message: WSGroupTypingMessage): void {
    const store = useMessageStore.getState();
    const { group_id, user_id, is_typing } = message;
    const groupIdStr = String(group_id);

    const currentTypingUsers = store.getTypingUsers(groupIdStr);
    let updatedTypingUsers: string[];

    if (is_typing) {
      if (!currentTypingUsers.includes(user_id)) {
        updatedTypingUsers = [...currentTypingUsers, user_id];
      } else {
        updatedTypingUsers = currentTypingUsers;
      }
    } else {
      updatedTypingUsers = currentTypingUsers.filter(id => id !== user_id);
    }

    if (updatedTypingUsers.length !== currentTypingUsers.length) {
      store.setTypingUsers(groupIdStr, updatedTypingUsers);
    }
  }

  /**
   * 处理群通知
   */
  handleGroupNotice(message: WSGroupNoticeMessage): void {
    const store = useMessageStore.getState();
    const { notice_type, group_id, data, timestamp, message_id, seq } = message;
    const groupIdStr = String(group_id);

    // 处理禁言/解除禁言通知
    if (notice_type === 'muted' || notice_type === 'unmuted') {
      const mutedUserId = data?.user_id;
      const currentUserId = this.getCurrentUserId();

      if (mutedUserId && mutedUserId === currentUserId) {
        const isMuted = notice_type === 'muted';
        store.setMutedStatus(groupIdStr, isMuted);
      }
    }

    // 补一条系统消息到当前会话消息流
    if (message_id && typeof seq === 'number' && seq > 0) {
      const conversationId = this.findConversationIdByGroupId(groupIdStr);
      if (conversationId) {
        const existingMessages = store.getMessages(conversationId);
        const exists = existingMessages.some(m => String(m.id) === String(message_id));
        if (!exists) {
          const noticeText = this.buildGroupNoticeText(notice_type, data);
          const systemNoticeMessage: MessageResponse = {
            id: String(message_id),
            conversation_id: conversationId,
            sender_id: '10000',
            seq,
            segments: noticeText
              ? [{ type: 'text', data: { text: noticeText } as any }]
              : [],
            status: 'normal',
            category: 'notification',
            created_at: new Date(timestamp || Date.now()).toISOString(),
          };

          const updatedMessages = [...existingMessages, systemNoticeMessage].sort((a, b) => a.seq - b.seq);
          store.setMessages(conversationId, updatedMessages);
        }
      }
    }
  }

  // ==================== 私有工具方法 ====================

  private updateConversationWithNewMessage(
    conversationId: string,
    message: MessageResponse,
    createdAt: string
  ): void {
    const store = useMessageStore.getState();
    const conversation = store.getConversation(conversationId);

    if (conversation) {
      const updatedConv: ConversationResponse = {
        ...conversation,
        last_seq: message.seq,
        last_message: message,
        last_message_at: createdAt,
        updated_at: createdAt,
      };
      store.updateConversation(updatedConv);
    }
  }

  private incrementUnreadCount(conversationId: string): void {
    const store = useMessageStore.getState();
    const conversation = store.getConversation(conversationId);
    if (conversation) {
      const prevUnreadCount = conversation.unread_count || 0;
      const updatedConv: ConversationResponse = {
        ...conversation,
        unread_count: prevUnreadCount + 1,
      };
      store.updateConversation(updatedConv);

      const currentUnread = store.getUnreadCount();
      store.setUnreadCount(currentUnread.total + 1, currentUnread.system);
    }
  }

  private markMessageAsRecalled(conversationId: string, messageId: string): void {
    const store = useMessageStore.getState();
    const messages = store.getMessages(conversationId);
    if (!messages) return;

    let changed = false;
    const updatedMessages: MessageResponse[] = messages.map((m): MessageResponse => {
      if (String(m.id) !== String(messageId) || m.status === 'recalled') {
        return m;
      }
      changed = true;
      return {
        ...m,
        status: 'recalled' as MessageResponse['status'],
        segments: [],
      };
    });

    if (!changed) return;

    store.setMessages(conversationId, updatedMessages);
  }

  private syncConversationLastMessageOnRecall(conversationId: string, messageId: string): void {
    const store = useMessageStore.getState();
    const conversation = store.getConversation(conversationId);
    if (!conversation?.last_message) return;
    if (String(conversation.last_message.id) !== String(messageId)) return;
    if (conversation.last_message.status === 'recalled') return;

    const updatedConversation: ConversationResponse = {
      ...conversation,
      last_message: {
        ...conversation.last_message,
        status: 'recalled',
      },
    };
    store.updateConversation(updatedConversation);
  }

  private findConversationIdByGroupId(groupId: string): string | null {
    const store = useMessageStore.getState();
    const conversations = store.getConversations();
    for (const conv of conversations) {
      if (String(conv.group?.id || '') === groupId) {
        return conv.id;
      }
    }
    return null;
  }

  private buildGroupNoticeText(noticeType: GroupNoticeType, data: any): string {
    const username = data?.username || '用户';
    switch (noticeType) {
      case 'member_join':
        return `"${username}" 加入了群聊`;
      case 'member_leave':
        return `"${username}" 退出了群聊`;
      case 'member_removed':
        return `"${username}" 被移出群聊`;
      case 'muted':
        return `"${username}" 已被管理员禁言`;
      case 'unmuted':
        return `"${username}" 已被管理员解除禁言`;
      default:
        return '';
    }
  }
}