import { useChatStore } from '@/stores/chatStore';
import { useSocketStore } from '@/stores/socketStore';
import type { ChatRoom, Message, MessageReaction } from '@/types';
import { io, type Socket } from 'socket.io-client';
import { toast } from 'sonner';

class SocketService {
  private socket: Socket | null = null;
  private listenersInitialized = false;

  connect(token: string): Socket {
    if (this.socket && this.socket.connected) {
      return this.socket;
    }
    const socketUrl = import.meta.env.DEV ? 'http://localhost:3000' : '';

    this.socket = io(socketUrl, {
      auth: {
        token,
      },
      path: '/socket.io',
    });
    if (!this.listenersInitialized) {
      this.setupEventListeners();
      this.listenersInitialized = true;
    }

    useSocketStore.getState().setSocket(this.socket);
    return this.socket;
  }

  disconnect() {
    if (this.socket) {
      this.removeAllListeners();
      this.socket.disconnect();
      this.socket = null;
      useSocketStore.getState().setSocket(null);
      useSocketStore.getState().setConnected(false);
    }
  }

  private removeAllListeners() {
    if (!this.socket) return;

    this.socket.removeAllListeners('new_message');
    this.socket.removeAllListeners('message_reaction_updated');
    this.socket.removeAllListeners('user_online');
    this.socket.removeAllListeners('user_offline');
    this.socket.removeAllListeners('rate_limit_exceeded');
    this.socket.removeAllListeners('error');
    this.socket.removeAllListeners('connect');
    this.socket.removeAllListeners('disconnect');
    this.socket.removeAllListeners('user_typing');
    this.socket.removeAllListeners('user_stopped_typing');
  }

  getSocket(): Socket | null {
    return this.socket;
  }

  private setupEventListeners() {
    if (!this.socket) return;

    this.removeAllListeners();

    const { setConnected } = useSocketStore.getState();
    const {
      addMessage,
      updateMessageReactions,
      addOnlineUser,
      removeOnlineUser,
      addTypingUser,
      removeTypingUser,
    } = useChatStore.getState();

    this.socket.on('connect', () => {
      console.log('Connected to server');
      setConnected(true);
    });

    this.socket.on('disconnect', () => {
      console.log('Disconnected from server');
      setConnected(false);
    });

    this.socket.on('new_message', (message: Message) => {
      addMessage(message);
    });

    this.socket.on(
      'message_reaction_updated',
      (data: { messageId: string; reactions: MessageReaction[] }) => {
        updateMessageReactions(data.messageId, data.reactions);
      }
    );

    this.socket.on(
      'user_online',
      (data: { userId: string; username: string }) => {
        addOnlineUser(data.userId);
      }
    );

    this.socket.on(
      'online_users',
      (users: { id: string; username: string[] }[]) => {
        const onlineUserIds = new Set(users.map((user) => user.id));
        useChatStore.getState().setOnlineUsers(onlineUserIds);
      }
    );

    this.socket.on(
      'user_offline',
      (data: { userId: string; username: string }) => {
        removeOnlineUser(data.userId);
      }
    );

    this.socket.on('chat_room_created', (room: ChatRoom) => {
      const { chatRooms, addChatRoom } = useChatStore.getState();

      if (!chatRooms.some((r) => r.id === room.id)) {
        addChatRoom(room);
        toast.success('Chat room created successfully', {
          id: 'creating-room',
        });
      }
    });

    this.socket.on(
      'rate_limit_exceeded',
      (data: { message: string; remainingTime?: number }) => {
        console.warn('Rate limit exceeded:', data.message);
        toast.error(`Rate limit exceeded: ${data.message}`, {
          duration: data.remainingTime ? data.remainingTime * 1000 : 5000,
          style: {
            background: '#f8d7da',
            color: '#721c24',
            border: '1px solid #f5c6cb',
          },
        });
      }
    );

    this.socket.on(
      'user_typing',
      (data: { roomId: string; username: string }) => {
        addTypingUser(data.roomId, data.username);
      }
    );

    this.socket.on(
      'user_stopped_typing',
      (data: { roomId: string; username: string }) => {
        removeTypingUser(data.roomId, data.username);
      }
    );

    this.socket.on(
      'message_seen_update',
      (data: { messageId: string; seenBy: string[] }) => {
        Object.keys(useChatStore.getState().messages).forEach((roomId) => {
          useChatStore.getState().messages[roomId].forEach((msg) => {
            if (msg.id === data.messageId) {
              msg.seenBy = data.seenBy;
            }
          });
        });
      }
    );

    this.socket.on('error', (data: { message: string }) => {
      console.error('Socket error:', data.message);
      toast.error(`Socket error: ${data.message}`, {
        duration: 5000,
        position: 'top-right',
      });
    });
  }
}

export const socketService = new SocketService();
