const { getSupabaseClient } = require('./supabaseClient');

class ChatSocketHandler {
  constructor(io) {
    this.io = io;
    this.onlineUsers = new Map(); // Хранение онлайн пользователей: socket.id -> user info
    this.chatRooms = new Map(); // Хранение участников комнат: chat_id -> Set(socket.id)
    this.setupSocketHandlers();
  }

  setupSocketHandlers() {
    this.io.on('connection', (socket) => {
      console.log(`User connected: ${socket.id}`);

      // Аутентификация пользователя
      socket.on('authenticate', async (data) => {
        await this.handleAuthentication(socket, data);
      });

      // Присоединение к чату
      socket.on('join_chat', async (data) => {
        await this.handleJoinChat(socket, data);
      });

      // Покидание чата
      socket.on('leave_chat', (data) => {
        this.handleLeaveChat(socket, data);
      });

      // Отправка сообщения
      socket.on('send_message', async (data) => {
        await this.handleSendMessage(socket, data);
      });

      // Пользователь начал печатать
      socket.on('typing_start', (data) => {
        this.handleTypingStart(socket, data);
      });

      // Пользователь закончил печатать
      socket.on('typing_stop', (data) => {
        this.handleTypingStop(socket, data);
      });

      // Отключение пользователя
      socket.on('disconnect', () => {
        this.handleDisconnect(socket);
      });
    });
  }

  async handleAuthentication(socket, data) {
    try {
      const { user_id, token } = data;
      
      if (!user_id) {
        socket.emit('auth_error', { message: 'user_id is required' });
        return;
      }

      // Получаем информацию о пользователе из базы данных
      const supabase = getSupabaseClient();
      const { data: userProfile, error } = await supabase
        .from('user_profiles')
        .select('*')
        .eq('id', user_id)
        .single();

      if (error) {
        socket.emit('auth_error', { message: 'User not found' });
        return;
      }

      // Сохраняем информацию о пользователе
      this.onlineUsers.set(socket.id, {
        user_id,
        socket_id: socket.id,
        profile: userProfile,
        last_seen: new Date()
      });

      socket.user_id = user_id;
      socket.emit('authenticated', { 
        message: 'Successfully authenticated',
        user: userProfile 
      });

      console.log(`User ${user_id} authenticated with socket ${socket.id}`);
    } catch (error) {
      console.error('Authentication error:', error);
      socket.emit('auth_error', { message: 'Authentication failed' });
    }
  }

  async handleJoinChat(socket, data) {
    try {
      const { chat_id } = data;
      
      if (!socket.user_id) {
        socket.emit('error', { message: 'Not authenticated' });
        return;
      }

      if (!chat_id) {
        socket.emit('error', { message: 'chat_id is required' });
        return;
      }

      // Проверяем, что чат существует и пользователь имеет доступ к нему
      const supabase = getSupabaseClient();
      const { data: chat, error } = await supabase
        .from('chats')
        .select(`
          *,
          buildings (
            management_company_id,
            apartments (
              apartment_residents (
                user_id
              )
            )
          )
        `)
        .eq('id', chat_id)
        .single();

      if (error || !chat) {
        socket.emit('error', { message: 'Chat not found' });
        return;
      }

      // Проверяем доступ пользователя к чату через квартиры в доме
      const hasAccess = chat.buildings.apartments.some(apartment =>
        apartment.apartment_residents.some(resident => 
          resident.user_id === socket.user_id
        )
      );

      if (!hasAccess) {
        socket.emit('error', { message: 'Access denied to this chat' });
        return;
      }

      // Добавляем сокет в комнату
      socket.join(chat_id);
      
      // Обновляем список участников комнаты
      if (!this.chatRooms.has(chat_id)) {
        this.chatRooms.set(chat_id, new Set());
      }
      this.chatRooms.get(chat_id).add(socket.id);

      socket.emit('joined_chat', { 
        chat_id, 
        chat: chat,
        message: 'Successfully joined chat' 
      });

      // Уведомляем других участников о подключении
      const userInfo = this.onlineUsers.get(socket.id);
      socket.to(chat_id).emit('user_joined', {
        chat_id,
        user: userInfo?.profile,
        timestamp: new Date()
      });

      console.log(`User ${socket.user_id} joined chat ${chat_id}`);
    } catch (error) {
      console.error('Join chat error:', error);
      socket.emit('error', { message: 'Failed to join chat' });
    }
  }

  handleLeaveChat(socket, data) {
    const { chat_id } = data;
    
    if (!chat_id) return;

    socket.leave(chat_id);
    
    // Удаляем из списка участников
    if (this.chatRooms.has(chat_id)) {
      this.chatRooms.get(chat_id).delete(socket.id);
      
      // Если комната пуста, удаляем её
      if (this.chatRooms.get(chat_id).size === 0) {
        this.chatRooms.delete(chat_id);
      }
    }

    // Уведомляем других участников об отключении
    const userInfo = this.onlineUsers.get(socket.id);
    socket.to(chat_id).emit('user_left', {
      chat_id,
      user: userInfo?.profile,
      timestamp: new Date()
    });

    console.log(`User ${socket.user_id} left chat ${chat_id}`);
  }

  async handleSendMessage(socket, data) {
    try {
      const { chat_id, text } = data;
      
      if (!socket.user_id) {
        socket.emit('error', { message: 'Not authenticated' });
        return;
      }

      if (!chat_id || !text) {
        socket.emit('error', { message: 'chat_id and text are required' });
        return;
      }

      // Сохраняем сообщение в базу данных
      const supabase = getSupabaseClient();
      const { data: message, error } = await supabase
        .from('messages')
        .insert({
          chat_id,
          user_id: socket.user_id,
          text
        })
        .select(`
          *,
          user_profiles (
            id,
            full_name,
            avatar_url
          )
        `)
        .single();

      if (error) {
        socket.emit('error', { message: 'Failed to save message' });
        return;
      }

      // Отправляем сообщение всем участникам чата
      this.io.to(chat_id).emit('new_message', {
        message,
        timestamp: new Date()
      });

      console.log(`Message sent to chat ${chat_id} by user ${socket.user_id}`);
    } catch (error) {
      console.error('Send message error:', error);
      socket.emit('error', { message: 'Failed to send message' });
    }
  }

  handleTypingStart(socket, data) {
    const { chat_id } = data;
    
    if (!socket.user_id || !chat_id) return;

    const userInfo = this.onlineUsers.get(socket.id);
    socket.to(chat_id).emit('user_typing_start', {
      chat_id,
      user: userInfo?.profile,
      timestamp: new Date()
    });
  }

  handleTypingStop(socket, data) {
    const { chat_id } = data;
    
    if (!socket.user_id || !chat_id) return;

    const userInfo = this.onlineUsers.get(socket.id);
    socket.to(chat_id).emit('user_typing_stop', {
      chat_id,
      user: userInfo?.profile,
      timestamp: new Date()
    });
  }

  handleDisconnect(socket) {
    console.log(`User disconnected: ${socket.id}`);
    
    // Удаляем пользователя из всех комнат
    this.chatRooms.forEach((participants, chat_id) => {
      if (participants.has(socket.id)) {
        participants.delete(socket.id);
        
        // Уведомляем других участников об отключении
        const userInfo = this.onlineUsers.get(socket.id);
        socket.to(chat_id).emit('user_left', {
          chat_id,
          user: userInfo?.profile,
          timestamp: new Date()
        });
        
        // Если комната пуста, удаляем её
        if (participants.size === 0) {
          this.chatRooms.delete(chat_id);
        }
      }
    });

    // Удаляем пользователя из списка онлайн
    this.onlineUsers.delete(socket.id);
  }

  // Получение списка онлайн пользователей в чате
  getOnlineUsersInChat(chat_id) {
    const participants = this.chatRooms.get(chat_id) || new Set();
    const onlineUsers = [];
    
    participants.forEach(socketId => {
      const userInfo = this.onlineUsers.get(socketId);
      if (userInfo) {
        onlineUsers.push(userInfo.profile);
      }
    });
    
    return onlineUsers;
  }

  // Отправка системного сообщения в чат
  async sendSystemMessage(chat_id, text) {
    this.io.to(chat_id).emit('system_message', {
      chat_id,
      text,
      timestamp: new Date()
    });
  }
}

// Функция инициализации Socket.IO для чатов
function initializeChatSocket(io) {
  const chatHandler = new ChatSocketHandler(io);
  return chatHandler;
}

module.exports = {
  ChatSocketHandler,
  initializeChatSocket
}; 