import { v4 as uuidv4 } from 'uuid';
import amqp from 'amqplib/callback_api.js';

const RABBITMQ_URL = 'amqp://localhost';
const QUEUE = 'oneToOne_messages';

class ChatService {
  constructor() {
    this.messages = [];
    this.searchQueue = [];
    this.users = [];
    this.randomChats = [];
    this.oneToOneChats = [];
    amqp.connect(RABBITMQ_URL, (err, connection) => {
      if (err) throw err;
      connection.createChannel((err, channel) => {
        if (err) throw err;
        this.channel = channel;
        channel.assertQueue(QUEUE, { durable: false });
      });
    });
  }

  getMessages(toId, fromId) {
    const userChats = this.randomChats.filter(chat => chat.includes(toId) && chat.includes(fromId));
    if (userChats.length === 0) {
      fromId = '';
    }
    const userMessages = this.messages.filter(message => message.to === toId && ["system", fromId].includes(message.from));
    this.messages = this.messages.filter(message => message.to === toId && ["system", fromId].includes(message.from));
    return userMessages;
  }

  async addMessage(from, to, text) {
    const userChats = this.randomChats.filter(chat => chat.includes(from) && chat.includes(to));
    if (userChats.length === 0) {
      return;
    }
    this.messages.push({ from: from, to: to, text: text });
    return { text: text };
  }

  findMatch(genders, age, id) {
    const currentUsersChat = this.randomChats.filter(chat => chat.includes(id));
    if (currentUsersChat.length > 0) {
      return this.findUser(currentUsersChat[0][0] === id ? currentUsersChat[0][1] : currentUsersChat[0][0]);
    }
    let filteredSearchQueue = this.users.filter(user =>
      this.searchQueue.some(sq => sq.id === user.id) && user.id !== id
      && this.randomChats.filter(chat => chat.includes(user.id)).length === 0
    ).sort(() => Math.random() - 0.5);

    for (let i = 0; i < filteredSearchQueue.length; i++) {
      const user = filteredSearchQueue[i];
      const ageMatch = user.age >= age.min && user.age <= age.max;
      const genderMatch = genders.includes(user.gender);
      if (ageMatch && genderMatch) {
        for (let j = this.searchQueue.length - 1; j >= 0; j--) {
          if ([id, user.id].includes(this.searchQueue[j].id)) {
            this.searchQueue.splice(j, 1);
          }
        }
        this.randomChats.push([user.id, id]);
        return user;
      }
    }
    if (!this.searchQueue.find(user => user.id === id)) {
      this.searchQueue.push({ id, genders, age });
    }
    return null;
  }

  findUser(id) {
    return this.users.find(user => user.id === id);
  }

  async registerUser(gender, age) {
    const id = uuidv4();
    this.users.push({ gender, age, id });
    return id;
  }

  async removeUser(id) {
    this.searchQueue = this.searchQueue.filter(user => user.id !== id);
    this.users = this.users.filter(user => user.id !== id);
    this.randomChats = this.randomChats.filter(pair => pair[0] === id || pair[1] === id);
    this.messages = this.messages.filter(message => message.from === id || message.to === id);
  }

  async endChat(userId) {
    this.randomChats = this.randomChats.filter(chat => !chat.includes(userId));
    this.messages.push({ to: userId, from: 'system', activity: 'otheruserleft' });
  }

  async initOneToOne(user1HashId, user2HashId) {
    const chat = this.searchOneToOneChat(user1HashId, user2HashId);
    if (!chat) {
      this.oneToOneChats.push({ user1Id: user1HashId, user2Id: user2HashId, history: [] });
    }
  }

  async sendOneToOneMessage(user1HashId, user2HashId, message) {
    const messageBundle = {
      timestamp: Date.now(),
      sender: user1HashId,
      recipient: user2HashId,
      message: message,
    };
    const chat = this.searchOneToOneChat(user1HashId, user2HashId);
    if (chat) {
      chat.history.push(messageBundle);
    } else {
      this.oneToOneChats.push({
        user1Id: user1HashId,
        user2Id: user2HashId,
        history: [messageBundle],
      });
    }
    if (this.channel) {
      this.channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(messageBundle)));
    }
  }

  async getOneToOneMessageHistory(user1HashId, user2HashId) {
    const chat = this.searchOneToOneChat(user1HashId, user2HashId);
    return chat ? chat.history : [];
  }

  searchOneToOneChat(user1HashId, user2HashId) {
    return this.oneToOneChats.find(chat =>
      (chat.user1Id === user1HashId && chat.user2Id === user2HashId) ||
      (chat.user1Id === user2HashId && chat.user2Id === user1HashId)
    );
  }
  
  async getRoomList() {
    // Nur öffentliche Räume, keine sensiblen Felder
    const { default: Room } = await import('../models/chat/room.js');
    const { default: RoomType } = await import('../models/chat/room_type.js');
    return Room.findAll({
      attributes: [
        'id', 'title', 'roomTypeId', 'isPublic', 'genderRestrictionId',
        'minAge', 'maxAge', 'friendsOfOwnerOnly', 'requiredUserRightId'
      ],
      where: { isPublic: true },
      include: [
        { model: RoomType, as: 'roomType' }
      ]
    });
  }
}

export default new ChatService();
