import {
    FindLocalidadesParams,
    ILocalidadesAdapter,
    ILocalidad,
    PaginateFilterBlockParams,
    PaginateFilterBlockResults,
} from "./Localidades.interface";
import mongoose, { Document, Model, Schema, model } from "mongoose";

export interface ILocalidadDocument extends Omit<ILocalidad, "id">, Document {}

export class LocalidadesAdapterMongoose implements ILocalidadesAdapter {
    schema: Schema;
    localidadList: Model<ILocalidadDocument>;

    constructor() {
        this.schema = new Schema({
            name: { type: String, required: true, unique: true },
            code: { type: Number, required: true, default: 0 },
            partido: { type: String, required: true },
            provincia: { type: String, required: true },
            latitude: { type: Number, required: true, default: 0 },
            longitude: { type: Number, required: true, default: 0 },
        });

        this.localidadList = model<ILocalidadDocument>("Localidade", this.schema);
    }

    public async find(filters: FindLocalidadesParams): Promise<ILocalidad[]> {
        return this.localidadList.find(filters).exec();
    }

    public async paginate(data: PaginateFilterBlockParams): Promise<PaginateFilterBlockResults> {
        const skip = (data.page - 1) * data.limit;

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

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

        if (data.name) {
            const words = data.name.split(" ").map((word) => new RegExp(word, "i"));
            searchCriteria.$and = words.map((word) => ({
                $or: [{ name: word }, { partido: word }, { provincia: word }],
            }));
        }

        // Realiza la consulta con paginación
        const results = await this.localidadList
            .find(searchCriteria)
            .sort({ price: 1 }) // Ordena por precio ascendente
            .skip(skip)
            .limit(data.limit)
            .exec();

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

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