import mongoose, { Document, Model, Schema, model } from "mongoose";
import {
    CreateMessageConversationParams,
    FindMessageConversationsParams,
    IMessageConversation,
    IMessageConversationsAdapter,
    PaginateMessageConversationsParams,
    PaginateMessageConversationsResults,
} from "./MessagesConversations.Interface";
import EmployeesList from "../Employees/Employee";

export interface IMessageConversationDocument extends Omit<IMessageConversation, "id">, Document {}

export class MessageConversationsAdapterMongoose implements IMessageConversationsAdapter {
    schema: Schema;
    conversationList: Model<IMessageConversationDocument>;

    constructor() {
        this.schema = new Schema({
            userIdFrom: { type: Schema.Types.ObjectId, required: false, ref: "User" },
            userIdTo: { type: Schema.Types.ObjectId, required: false, ref: "User" },
            companyId: { type: Schema.Types.ObjectId, required: false, ref: "Companie" },
            type: { type: String, required: true },
        });

        this.conversationList = model<IMessageConversationDocument>(
            "MessagesConversation",
            this.schema
        );
    }

    public async create(data: CreateMessageConversationParams): Promise<IMessageConversation> {
        return await this.conversationList.create(data);
    }

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

    public async find(
        filters: Omit<FindMessageConversationsParams, "sessionUser">
    ): Promise<IMessageConversation[]> {
        return this.conversationList.find(filters).exec();
    }

    public async findOne(
        filters: Omit<FindMessageConversationsParams, "sessionUser">
    ): Promise<IMessageConversationDocument | null> {
        return this.conversationList.findOne(filters).exec();
    }

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

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

        // 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 }];
        }

        //Busca las organizaciones en las que el usuario es colaborador
        const collaboratorOrgs = await EmployeesList.employees.find({
            userId: data.sessionUser,
        });

        const orgIds = collaboratorOrgs.map((org) => org.companyId);

        searchCriteria.$or = [
            { userIdFrom: data.sessionUser },
            { userIdTo: data.sessionUser },
            { companyId: { $in: orgIds } },
        ];

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

        if (data.userIdTo !== undefined) {
            searchCriteria.userIdTo = data.userIdTo;
        }

        if (data.companyId !== undefined) {
            searchCriteria.companyId = data.companyId;
        }

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

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

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