/**
 * Messaging State Slice
 * Manages conversations and messages
 */

import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';

export interface Message {
  id: string;
  conversationId: string;
  senderId: string;
  content: string;
  encrypted: boolean;
  createdAt: string;
  status: 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
}

export interface Conversation {
  id: string;
  type: 'direct' | 'group';
  participants: string[];
  lastMessage?: Message;
  unreadCount: number;
  createdAt: string;
  updatedAt: string;
}

interface MessagingState {
  conversations: Record<string, Conversation>;
  messages: Record<string, Message[]>; // conversationId -> messages
  activeConversationId: string | null;
  loading: boolean;
  error: string | null;
}

const initialState: MessagingState = {
  conversations: {},
  messages: {},
  activeConversationId: null,
  loading: false,
  error: null,
};

// Async thunks
export const fetchConversations = createAsyncThunk(
  'messaging/fetchConversations',
  async (_, { rejectWithValue }) => {
    try {
      const response = await fetch('/api/conversations', {
        headers: {
          'Authorization': `Bearer ${localStorage.getItem('token')}`,
        },
      });
      
      if (!response.ok) {
        throw new Error('Failed to fetch conversations');
      }
      
      const data = await response.json();
      return data.conversations;
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

export const fetchMessages = createAsyncThunk(
  'messaging/fetchMessages',
  async (conversationId: string, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/conversations/${conversationId}/messages`, {
        headers: {
          'Authorization': `Bearer ${localStorage.getItem('token')}`,
        },
      });
      
      if (!response.ok) {
        throw new Error('Failed to fetch messages');
      }
      
      const data = await response.json();
      return { conversationId, messages: data.messages };
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

export const sendMessage = createAsyncThunk(
  'messaging/sendMessage',
  async ({ conversationId, content }: { conversationId: string; content: string }, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/conversations/${conversationId}/messages`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${localStorage.getItem('token')}`,
        },
        body: JSON.stringify({ content }),
      });
      
      if (!response.ok) {
        throw new Error('Failed to send message');
      }
      
      const data = await response.json();
      return data.message;
    } catch (error: any) {
      return rejectWithValue(error.message);
    }
  }
);

// Slice
const messagingSlice = createSlice({
  name: 'messaging',
  initialState,
  reducers: {
    setActiveConversation: (state, action: PayloadAction<string>) => {
      state.activeConversationId = action.payload;
    },
    addMessage: (state, action: PayloadAction<Message>) => {
      const message = action.payload;
      const conversationId = message.conversationId;
      
      if (!state.messages[conversationId]) {
        state.messages[conversationId] = [];
      }
      
      state.messages[conversationId].push(message);
      
      // Update last message in conversation
      if (state.conversations[conversationId]) {
        state.conversations[conversationId].lastMessage = message;
        state.conversations[conversationId].updatedAt = message.createdAt;
      }
    },
    updateMessageStatus: (state, action: PayloadAction<{ messageId: string; status: Message['status'] }>) => {
      const { messageId, status } = action.payload;
      
      for (const conversationId in state.messages) {
        const message = state.messages[conversationId].find(m => m.id === messageId);
        if (message) {
          message.status = status;
          break;
        }
      }
    },
    markAsRead: (state, action: PayloadAction<string>) => {
      const conversationId = action.payload;
      if (state.conversations[conversationId]) {
        state.conversations[conversationId].unreadCount = 0;
      }
      
      // Update message statuses
      if (state.messages[conversationId]) {
        state.messages[conversationId].forEach(message => {
          if (message.status === 'delivered') {
            message.status = 'read';
          }
        });
      }
    },
    incrementUnread: (state, action: PayloadAction<string>) => {
      const conversationId = action.payload;
      if (state.conversations[conversationId]) {
        state.conversations[conversationId].unreadCount++;
      }
    },
  },
  extraReducers: (builder) => {
    // Fetch conversations
    builder.addCase(fetchConversations.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(fetchConversations.fulfilled, (state, action) => {
      state.loading = false;
      action.payload.forEach((conv: Conversation) => {
        state.conversations[conv.id] = conv;
      });
    });
    builder.addCase(fetchConversations.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload as string;
    });
    
    // Fetch messages
    builder.addCase(fetchMessages.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(fetchMessages.fulfilled, (state, action) => {
      state.loading = false;
      const { conversationId, messages } = action.payload;
      state.messages[conversationId] = messages;
    });
    builder.addCase(fetchMessages.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload as string;
    });
    
    // Send message
    builder.addCase(sendMessage.fulfilled, (state, action) => {
      const message = action.payload;
      const conversationId = message.conversationId;
      
      if (!state.messages[conversationId]) {
        state.messages[conversationId] = [];
      }
      
      state.messages[conversationId].push(message);
      
      // Update conversation
      if (state.conversations[conversationId]) {
        state.conversations[conversationId].lastMessage = message;
        state.conversations[conversationId].updatedAt = message.createdAt;
      }
    });
  },
});

export const {
  setActiveConversation,
  addMessage,
  updateMessageStatus,
  markAsRead,
  incrementUnread,
} = messagingSlice.actions;

export default messagingSlice.reducer;
