import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { devtools } from 'zustand/middleware';

export interface ChatMessage {
  id: string;
  conversation_id: string;
  sender_id: string; // User ID
  sender_username: string; // For display purposes
  content: string;
  created_at: string;
  reactions?: Record<string, string[]>; // emoji -> userIds[]
  attachments?: import('../types').MessageAttachment[];
  // status: 'sent' | 'delivered' | 'read' | 'error';
  // type: 'text' | 'image' | 'audio' | 'video' | 'file';
}

export interface Conversation {
  id: string; // UUID from backend
  name: string; // For rooms
  type: 'public' | 'private' | 'direct';
  participants: string[]; // User IDs
  last_message?: ChatMessage;
  unread_count: number;
}

export interface ChatState {
  userId: string | null; // Current authenticated user ID
  username: string | null;
  currentConversationId: string | null;
  conversations: Conversation[];
  messages: Record<string, ChatMessage[]>; // conversationId -> messages[]
  typingUsers: Record<string, string[]>; // conversationId -> userIds[]
  wsToken: string | null;
  wsUrl: string | null;
  wsStatus: 'disconnected' | 'connecting' | 'connected' | 'error';

  // Actions
  setUserId: (userId: string | null, username: string | null) => void;
  setWsToken: (token: string, wsUrl: string) => void;
  setWsStatus: (
    status: 'disconnected' | 'connecting' | 'connected' | 'error',
  ) => void;
  addConversation: (conversation: Conversation) => void;
  setCurrentConversation: (conversationId: string | null) => void;
  addMessage: (message: ChatMessage) => void;
  loadMessages: (conversationId: string, newMessages: ChatMessage[]) => void;
  addReaction: (
    conversationId: string,
    messageId: string,
    userId: string,
    emoji: string,
  ) => void;
  removeReaction: (
    conversationId: string,
    messageId: string,
    userId: string,
  ) => void;
  setUserTyping: (
    conversationId: string,
    userId: string,
    isTyping: boolean,
  ) => void;
}

export const useChatStore = create<ChatState>()(
  devtools(
    immer((set) => ({
      userId: null,
      username: null,
      currentConversationId: null,
      conversations: [],
      messages: {},
      typingUsers: {},
      wsToken: null,
      wsUrl: null,
      wsStatus: 'disconnected',

      setUserId: (userId, username) =>
        set((state) => {
          state.userId = userId;
          state.username = username;
        }),
      setWsToken: (token, wsUrl) =>
        set((state) => {
          state.wsToken = token;
          state.wsUrl = wsUrl;
        }),
      setWsStatus: (status) =>
        set((state) => {
          state.wsStatus = status;
        }),
      addConversation: (conversation) =>
        set((state) => {
          if (!state.conversations.some((c) => c.id === conversation.id)) {
            state.conversations.push(conversation);
          }
        }),
      setCurrentConversation: (conversationId) =>
        set((state) => {
          state.currentConversationId = conversationId;
        }),
      addMessage: (message) =>
        set((state) => {
          if (!state.messages[message.conversation_id]) {
            state.messages[message.conversation_id] = [];
          }
          state.messages[message.conversation_id].push(message);
        }),
      loadMessages: (conversationId, newMessages) =>
        set((state) => {
          const existing = state.messages[conversationId] || [];

          // Create a Set of IDs from newMessages for efficient lookup
          const newMessageIds = new Set(newMessages.map((m) => m.id));

          // Keep existing messages that are NOT in the new batch
          // (these are likely real-time messages that arrived after fetch started)
          const realtimeMessages = existing.filter(
            (m) => !newMessageIds.has(m.id),
          );

          // Merge: combine real-time messages with history
          const merged = [...realtimeMessages, ...newMessages];

          // Sort by created_at to maintain chronological order
          merged.sort(
            (a, b) =>
              new Date(a.created_at).getTime() -
              new Date(b.created_at).getTime(),
          );

          state.messages[conversationId] = merged;
        }),
      addReaction: (conversationId, messageId, userId, emoji) =>
        set((state) => {
          const messages = state.messages[conversationId];
          if (messages) {
            const message = messages.find((m) => m.id === messageId);
            if (message) {
              if (!message.reactions) message.reactions = {};
              // Remove existing reaction from this user if any
              Object.keys(message.reactions).forEach((e) => {
                message.reactions![e] = message.reactions![e].filter(
                  (id) => id !== userId,
                );
                if (message.reactions![e].length === 0)
                  delete message.reactions![e];
              });
              // Add new reaction
              if (!message.reactions[emoji]) message.reactions[emoji] = [];
              if (!message.reactions[emoji].includes(userId)) {
                message.reactions[emoji].push(userId);
              }
            }
          }
        }),
      removeReaction: (conversationId, messageId, userId) =>
        set((state) => {
          const messages = state.messages[conversationId];
          if (messages) {
            const message = messages.find((m) => m.id === messageId);
            if (message && message.reactions) {
              Object.keys(message.reactions).forEach((emoji) => {
                message.reactions![emoji] = message.reactions![emoji].filter(
                  (id) => id !== userId,
                );
                if (message.reactions![emoji].length === 0)
                  delete message.reactions![emoji];
              });
            }
          }
        }),
      setUserTyping: (conversationId, userId, isTyping) =>
        set((state) => {
          if (!state.typingUsers[conversationId])
            state.typingUsers[conversationId] = [];
          if (isTyping) {
            if (!state.typingUsers[conversationId].includes(userId)) {
              state.typingUsers[conversationId].push(userId);
            }
          } else {
            state.typingUsers[conversationId] = state.typingUsers[
              conversationId
            ].filter((id) => id !== userId);
          }
        }),
    })),
    {
      name: 'ChatStore',
      enabled: import.meta.env.DEV,
    },
  ),
);
