import mongoose, { Document, Model, Schema, model } from "mongoose";
import {
    CreateMessageParams,
    FindMessageParams,
    IMessage,
    IMessagesAdapter,
    PaginateMessageParams,
    PaginateMessageResults,
} from "./Messages.Interface";

export interface IMessageDocument extends Omit<IMessage, "id">, Document {}

export class MessagesAdapterMongoose implements IMessagesAdapter {
    schema: Schema;
    messageList: Model<IMessageDocument>;

    constructor() {
        this.schema = new Schema({
            conversationId: {
                type: Schema.Types.ObjectId,
                required: true,
                ref: "MessagesConversation",
            },
            userId: {
                type: Schema.Types.ObjectId,
                required: true,
                ref: "User",
            },
            message: { type: String, required: true },
            messageDate: { type: Date, required: true },
            readed: { type: Boolean, default: false },
        });

        this.messageList = model<IMessageDocument>("Message", this.schema);
    }

    public async create(data: CreateMessageParams): Promise<IMessage> {
        return await this.messageList.create({
            conversationId: data.conversationId,
            userId: data.sessionUser,
            message: data.message,
            messageDate: new Date(),
            readed: false,
        });
    }

    public async delete(id: string): Promise<void> {
        await this.messageList.findByIdAndDelete(id).exec();
    }

    public async find(filters: Omit<FindMessageParams, "sessionUser">): Promise<IMessage[]> {
        return this.messageList.find(filters).exec();
    }

    public async findOne(
        filters: Omit<FindMessageParams, "sessionUser">
    ): Promise<IMessage | null> {
        return this.messageList.findOne(filters).exec();
    }

    // Método para búsqueda con expresiones regulares y paginación
    public async paginate(data: PaginateMessageParams): Promise<PaginateMessageResults> {
        const skip = (data.page - 1) * data.limit;

        // Construye los criterios de búsqueda
        const searchCriteria: mongoose.FilterQuery<IMessage> = {};

        // Agrega filtro por query usando expresiones regulares para 'name' y 'description'
        if (data.query) {
            const regex = new RegExp(data.query, "i");
            searchCriteria.$or = [{ subject: regex }, { message: regex }];
        }

        // Filtra por categoryId si está presente
        if (data.conversationId !== undefined) {
            searchCriteria.conversationId = data.conversationId;
        }

        if (data.readed) {
            searchCriteria.readed = data.readed;
        }

        // Realiza la consulta con paginación
        const results = await this.messageList
            .find(searchCriteria)
            .sort({ messageDate: -1 })
            .skip(skip)
            .limit(data.limit)
            .exec();

        // Cuenta el total de documentos que coinciden con los criterios de búsqueda
        const count = await this.messageList.countDocuments(searchCriteria).exec();

        return {
            data: results,
            page: data.page,
            pages: Math.ceil(count / data.limit),
        };
    }

    public async markAsRead(data: FindMessageParams): Promise<void> {
        await this.messageList.updateMany(
            { conversationId: data.conversationId },
            { $set: { readed: true } }
        );
    }
}
