import { Injectable } from "@nestjs/common"
import { Repository } from "typeorm"
import { InjectRepository } from "@nestjs/typeorm"
import {
  ChatMessage,
  SenderType,
  ReceiverType,
  ParticipantRoleType,
} from "../entities/chat-message.entity"

@Injectable()
export class ChatMessageRepository {
  constructor(
    @InjectRepository(ChatMessage)
    private readonly chatMessageEntity: Repository<ChatMessage>,
  ) {}

  async save(messageData: Partial<ChatMessage>): Promise<ChatMessage> {
    const message = this.chatMessageEntity.create(messageData)
    return await this.chatMessageEntity.save(message)
  }

  async findByParams(options: {
    where?: any
    relations?: string[]
    select?: string[]
    orderBy?: any
    take?: number
    skip?: number
    findOne?: boolean
  }): Promise<ChatMessage | ChatMessage[]> {
    const query = this.chatMessageEntity.createQueryBuilder("message")

    if (options.where) {
      Object.entries(options.where).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          query.andWhere(`message.${key} IN (:...${key})`, { [key]: value })
        } else {
          query.andWhere(`message.${key} = :${key}`, { [key]: value })
        }
      })
    }

    if (options.relations && options.relations.length > 0) {
      options.relations.forEach((relation) => {
        query.leftJoinAndSelect(`message.${relation}`, relation)
      })
    }

    if (options.select && options.select.length > 0) {
      query.select(options.select.map((field) => `message.${field}`))
    }

    if (options.orderBy) {
      Object.entries(options.orderBy).forEach(([field, direction]) => {
        query.orderBy(`message.${field}`, direction as "ASC" | "DESC")
      })
    }

    if (options.take) {
      query.take(options.take)
    }

    if (options.skip) {
      query.skip(options.skip)
    }

    if (options.findOne) {
      return await query.getOne()
    }

    return await query.getMany()
  }

  async getChatHistory(
    chatRoomId: number,
    limit = 50,
    skip = 0,
  ): Promise<ChatMessage[]> {
    return await this.chatMessageEntity
      .createQueryBuilder("message")
      .leftJoinAndSelect("message.chat_room", "chat_room")
      .where("message.chat_room_id = :chatRoomId", { chatRoomId })
      .orderBy("message.created_at", "DESC")
      .take(limit)
      .skip(skip)
      .getMany()
  }

  async markMessagesAsRead(
    chatRoomId: number,
    userId: number,
    userType: ParticipantRoleType,
  ): Promise<void> {
    await this.chatMessageEntity
      .createQueryBuilder()
      .update(ChatMessage)
      .set({ is_read: true })
      .where("chat_room_id = :chatRoomId", { chatRoomId })
      .andWhere(`(receiver_type = :userType AND receiver_id = :userId)`, {
        chatRoomId,
        userType,
        userId,
      })
      .execute()
  }

  async getUnreadCount(
    participantType: string,
    participantId: number,
  ): Promise<number> {
    return await this.chatMessageEntity
      .createQueryBuilder("message")
      .leftJoin("message.chat_room", "chat_room")
      .leftJoin("chat_room.participants", "participant")
      .where("participant.participant_type = :participantType", {
        participantType,
      })
      .andWhere("participant.participant_id = :participantId", {
        participantId,
      })
      .andWhere("message.is_read = false")
      .andWhere("message.receiver_type = :participantType", {
        participantType,
      })
      .andWhere("message.receiver_id != :participantId", {
        participantId,
      })
      .getCount()
  }

  async saveMessage(
    chatRoomId: number,
    senderType: SenderType,
    senderId: number,
    receiverType: ReceiverType,
    receiverId: number,
    messageText: string,
  ): Promise<ChatMessage> {
    return await this.save({
      chat_room_id: chatRoomId,
      sender_type: senderType,
      sender_id: senderId,
      receiver_type: receiverType,
      receiver_id: receiverId,
      message_text: messageText,
    })
  }
}
