import type { ImApi } from '#/api/core/im';

import { computed, ref } from 'vue';

import { useUserStore } from '@vben/stores';

import { defineStore } from 'pinia';

import {
  createPrivateConversationApi,
  getConversationsApi,
  getMessageHistoryApi,
  getUnreadCountApi,
  searchUsersApi,
} from '#/api/core/im';
import { signalRService } from '#/api/core/signalr';

export const useImStore = defineStore('im', () => {
  const conversations = ref<ImApi.Conversation[]>([]);
  const activeConversationId = ref<null | string>(null);
  const messages = ref<Map<string, ImApi.Message[]>>(new Map());
  const unreadCounts = ref<Map<string, number>>(new Map());
  const onlineUsers = ref<Set<string>>(new Set());
  const connected = ref(false);
  const typingUsers = ref<Map<string, Set<string>>>(new Map());
  const contacts = ref<ImApi.User[]>([]);
  const contactsLoading = ref(false);

  const totalUnread = computed(() => {
    let total = 0;
    for (const count of unreadCounts.value.values()) {
      total += count;
    }
    return total;
  });

  const activeMessages = computed(() => {
    if (!activeConversationId.value) return [];
    return messages.value.get(activeConversationId.value) ?? [];
  });

  const activeConversation = computed(() => {
    if (!activeConversationId.value) return null;
    return conversations.value.find((c) => c.id === activeConversationId.value);
  });

  async function connect() {
    signalRService.onMessageReceived = (message) => {
      const convMessages = messages.value.get(message.conversationId) ?? [];
      convMessages.push(message);
      messages.value.set(message.conversationId, convMessages);

      // Update conversation last message
      const conv = conversations.value.find(
        (c) => c.id === message.conversationId,
      );
      if (conv) {
        conv.lastMessageContent =
          message.contentType === 0
            ? message.content.slice(0, 50)
            : `[${['文本', '图片', '文件', '系统', '表情'][message.contentType] || '消息'}]`;
        conv.lastMessageAt = message.createdAt;
      }

      // Increment unread if not active conversation
      if (message.conversationId !== activeConversationId.value) {
        const current = unreadCounts.value.get(message.conversationId) ?? 0;
        unreadCounts.value.set(message.conversationId, current + 1);
        const conv2 = conversations.value.find(
          (c) => c.id === message.conversationId,
        );
        if (conv2) conv2.unreadCount++;
      }
    };

    signalRService.onUserOnline = (data) => {
      onlineUsers.value.add(data.userId);
    };

    signalRService.onUserOffline = (data) => {
      onlineUsers.value.delete(data.userId);
    };

    signalRService.onUserTyping = (data) => {
      if (!typingUsers.value.has(data.conversationId)) {
        typingUsers.value.set(data.conversationId, new Set());
      }
      typingUsers.value.get(data.conversationId)?.add(data.userId);
      setTimeout(() => {
        typingUsers.value.get(data.conversationId)?.delete(data.userId);
      }, 3000);
    };

    await signalRService.connect();
    connected.value = signalRService.isConnected;
  }

  async function disconnect() {
    await signalRService.disconnect();
    connected.value = false;
  }

  async function loadConversations() {
    const data = await getConversationsApi();
    conversations.value = data;
  }

  async function loadMessages(conversationId: string, beforeId?: string) {
    const data = await getMessageHistoryApi(conversationId, beforeId);
    if (beforeId) {
      const existing = messages.value.get(conversationId) ?? [];
      messages.value.set(conversationId, [...data.messages, ...existing]);
    } else {
      messages.value.set(conversationId, data.messages);
    }
    return data.hasMore;
  }

  async function loadUnreadCounts() {
    const data = await getUnreadCountApi();
    const map = new Map<string, number>();
    for (const item of data.items) {
      map.set(item.conversationId, item.unreadCount);
    }
    unreadCounts.value = map;
  }

  async function sendMessage(
    conversationId: string,
    contentType: number,
    content: string,
    metadata?: any,
    replyToId?: string,
  ) {
    await signalRService.sendMessage({
      conversationId,
      contentType,
      content,
      metadata,
      replyToId,
    });
  }

  async function markAsRead(conversationId: string, messageId: string) {
    await signalRService.markAsRead(conversationId, messageId);
    unreadCounts.value.set(conversationId, 0);
    const conv = conversations.value.find((c) => c.id === conversationId);
    if (conv) conv.unreadCount = 0;
  }

  async function typing(conversationId: string) {
    await signalRService.typing(conversationId);
  }

  function setActiveConversation(conversationId: null | string) {
    activeConversationId.value = conversationId;
  }

  async function searchContacts(query?: string) {
    contactsLoading.value = true;
    try {
      const userStore = useUserStore();
      const data = await searchUsersApi(query);
      contacts.value = data.filter((u) => u.id !== userStore.userInfo?.userId);
    } finally {
      contactsLoading.value = false;
    }
  }

  async function startPrivateChat(targetUserId: string) {
    const conversation = await createPrivateConversationApi(targetUserId);
    await loadConversations();
    setActiveConversation(conversation.id);
    await loadMessages(conversation.id);
    return conversation;
  }

  return {
    // State
    conversations,
    activeConversationId,
    messages,
    unreadCounts,
    onlineUsers,
    connected,
    typingUsers,
    contacts,
    contactsLoading,
    // Computed
    totalUnread,
    activeMessages,
    activeConversation,
    // Actions
    connect,
    disconnect,
    loadConversations,
    loadMessages,
    loadUnreadCounts,
    sendMessage,
    markAsRead,
    typing,
    setActiveConversation,
    searchContacts,
    startPrivateChat,
  };
});
