import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';
import { wsService } from '@/services/websocket';
import { normalizeObjectIds } from '@/utils/idNormalization';
import type { ChatMessage, Conversation, ChatWebSocketEvent } from '@/types';

// FE-TYPE-011: Fully typed store interfaces
export interface ChatState {
  conversations: Conversation[];
  currentConversation: Conversation | null;
  messages: Record<string, ChatMessage[]>;
  typingUsers: Record<string, string[]>;
  isConnected: boolean;
  isLoading: boolean;
  error: string | null;
}

export interface ChatActions {
  setConversations: (conversations: Conversation[]) => void;
  setCurrentConversation: (conversation: Conversation | null) => void;
  addMessage: (conversationId: string, message: ChatMessage) => void;
  updateMessage: (
    conversationId: string,
    messageId: string,
    updates: Partial<ChatMessage>,
  ) => void;
  removeMessage: (conversationId: string, messageId: string) => void;
  setMessages: (conversationId: string, messages: ChatMessage[]) => void;
  setTypingUsers: (conversationId: string, userIds: string[]) => void;
  addTypingUser: (conversationId: string, userId: string) => void;
  removeTypingUser: (conversationId: string, userId: string) => void;
  setConnected: (connected: boolean) => void;
  setLoading: (loading: boolean) => void;
  setError: (error: string | null) => void;
  connect: () => Promise<void>;
  disconnect: () => void;
  joinConversation: (conversationId: string) => void;
  leaveConversation: (conversationId: string) => void;
  sendMessage: (
    conversationId: string,
    content: string,
    parentMessageId?: string,
  ) => void;
  startTyping: (conversationId: string) => void;
  stopTyping: (conversationId: string) => void;
  addReaction: (messageId: string, emoji: string) => void;
  removeReaction: (messageId: string, emoji: string) => void;
  fetchConversations: () => Promise<void>;
  createConversation: (params: {
    name: string;
    description?: string;
    type?: 'public' | 'private' | 'direct';
    is_private?: boolean;
  }) => Promise<Conversation>;
}

// FE-TYPE-011: Export store type for reuse
export type ChatStore = ChatState & ChatActions;

export const useChatStore = create<ChatStore>()(
  devtools(
    persist(
      (set, get) => ({
  // État initial
  conversations: [],
  currentConversation: null,
  messages: {},
  typingUsers: {},
  isConnected: false,
  isLoading: false,
  error: null,

  // Actions
  setConversations: (conversations) => set({ conversations }),

  setCurrentConversation: (conversation) => {
    set({ currentConversation: conversation });
    if (conversation) {
      get().joinConversation(conversation.id);
    }
  },

  addMessage: (conversationId, message) => {
    set((state) => ({
      messages: {
        ...state.messages,
        [conversationId]: [...(state.messages[conversationId] || []), message],
      },
    }));
  },

  updateMessage: (conversationId, messageId, updates) => {
    set((state) => ({
      messages: {
        ...state.messages,
        [conversationId]:
          state.messages[conversationId]?.map((msg) =>
            msg.id === messageId ? { ...msg, ...updates } : msg,
          ) || [],
      },
    }));
  },

  removeMessage: (conversationId, messageId) => {
    set((state) => ({
      messages: {
        ...state.messages,
        [conversationId]:
          state.messages[conversationId]?.filter(
            (msg) => msg.id !== messageId,
          ) || [],
      },
    }));
  },

  setMessages: (conversationId, messages) => {
    set((state) => ({
      messages: {
        ...state.messages,
        [conversationId]: messages,
      },
    }));
  },

  setTypingUsers: (conversationId, userIds) => {
    set((state) => ({
      typingUsers: {
        ...state.typingUsers,
        [conversationId]: userIds,
      },
    }));
  },

  addTypingUser: (conversationId, userId) => {
    set((state) => ({
      typingUsers: {
        ...state.typingUsers,
        [conversationId]: [
          ...(state.typingUsers[conversationId] || []),
          userId,
        ],
      },
    }));
  },

  removeTypingUser: (conversationId, userId) => {
    set((state) => ({
      typingUsers: {
        ...state.typingUsers,
        [conversationId]: (state.typingUsers[conversationId] || []).filter(
          (id) => id !== userId,
        ),
      },
    }));
  },

  setConnected: (isConnected) => set({ isConnected }),

  setLoading: (isLoading) => set({ isLoading }),

  setError: (error) => set({ error }),

  connect: async () => {
    set({ isLoading: true, error: null });
    try {
      await wsService.connect();
      set({ isConnected: true, isLoading: false });

      // Écouter les événements WebSocket
      wsService.on('message', (event: ChatWebSocketEvent) => {
        const { conversation_id, user_id, content, emoji, timestamp } =
          event.data;

        switch (event.type) {
          case 'message':
            if (content) {
              get().addMessage(conversation_id, {
                id: crypto.randomUUID(),
                conversation_id,
                sender_id: user_id,
                content,
                created_at: timestamp,
              });
            }
            break;
          case 'typing':
            get().addTypingUser(conversation_id, user_id);
            // Retirer l'utilisateur de la liste après 3 secondes
            setTimeout(() => {
              get().removeTypingUser(conversation_id, user_id);
            }, 3000);
            break;
          case 'reaction':
            if (emoji) {
              // Mettre à jour les réactions du message
              // Cette logique dépend de la structure des données
            }
            break;
        }
      });

      wsService.on('connected', () => {
        set({ isConnected: true, isLoading: false });
      });

      wsService.on('disconnected', () => {
        set({ isConnected: false });
      });

      wsService.on('error', (error: any) => {
        set({ error: error.message, isLoading: false });
      });
    } catch (error: any) {
      set({ error: error.message, isLoading: false });
    }
  },

  disconnect: () => {
    wsService.disconnect();
    set({ isConnected: false });
  },

  joinConversation: (conversationId) => {
    wsService.joinConversation(conversationId);
  },

  leaveConversation: (conversationId) => {
    wsService.leaveConversation(conversationId);
  },

  sendMessage: (conversationId, content, parentMessageId) => {
    wsService.sendMessage(conversationId, content, parentMessageId);
  },

  startTyping: (conversationId) => {
    wsService.startTyping(conversationId);
  },

  stopTyping: (conversationId) => {
    wsService.stopTyping(conversationId);
  },

  addReaction: (messageId, emoji) => {
    wsService.addReaction(messageId, emoji);
  },

  removeReaction: (messageId, emoji) => {
    wsService.removeReaction(messageId, emoji);
  },

  fetchConversations: async () => {
    try {
      const { apiClient } = await import('@/services/api/client');
      const response = await apiClient.get<{ conversations: Conversation[] }>('/conversations');
      // apiClient unwrap déjà le format { success, data }
      const data = response.data;
      // FE-TYPE-001: Normalize all IDs to strings
      const conversations = (data.conversations || []).map((conv: any) => {
        const normalized = normalizeObjectIds(conv);
        return {
          ...normalized,
          name: normalized.name || `Conversation ${normalized.id}`,
          participants: (normalized.participants || []).map((p: any) =>
            typeof p === 'string' ? p : normalizeObjectIds(p).id || String(p),
          ),
        };
      });
      set({ conversations });
    } catch (error) {
      console.error('Error fetching conversations:', error);
      set({ error: 'Failed to fetch conversations' });
    }
  },

  createConversation: async (params) => {
    try {
      const { apiClient } = await import('@/services/api/client');
      const response = await apiClient.post<Conversation>('/conversations', {
        name: params.name,
        description: params.description || '',
        type: params.type || 'public',
        is_private: params.is_private || false,
      });
      // apiClient unwrap déjà le format { success, data }
      const conv = response.data;
      // FE-TYPE-001: Normalize all IDs to strings
      const normalized = normalizeObjectIds(conv);
      const conversation: Conversation = {
        ...normalized,
        name: normalized.name || `Conversation ${normalized.id}`,
        participants: (normalized.participants || []).map((p: any) =>
          typeof p === 'string' ? p : normalizeObjectIds(p).id || String(p),
        ),
      };

      // Ajouter la nouvelle conversation à la liste
      set((state) => ({
        conversations: [...state.conversations, conversation],
        currentConversation: conversation,
      }));

      // Rejoindre la conversation via WebSocket
      get().joinConversation(conversation.id);

      return conversation;
    } catch (error: any) {
      console.error('Error creating conversation:', error);
      set({ error: error.message || 'Failed to create conversation' });
      throw error;
    }
  },
      }),
      {
        name: 'chat-storage',
        partialize: (state) => ({
          // FE-STATE-001: Persist conversations for offline support
          // Don't persist messages as they can be large and should be fetched fresh
          conversations: state.conversations,
          currentConversation: state.currentConversation,
          // Don't persist messages, typingUsers, isConnected, isLoading, error
        }),
      },
    ),
    {
      // FE-STATE-007: Enable Redux DevTools for debugging
      name: 'ChatStore',
      enabled: import.meta.env.DEV,
    },
  ),
);
