import {
    IFavourite,
    IFavouriteDocument,
    IFavouritesAdapter,
    CreateFavouriteParams,
    DeleteFavouriteParams,
    FindFavouritesParams,
    PaginateFavouritesParams,
    PaginateFavouritesResults,
} from "./Favourites.interface";
import { Schema, model, Model, FilterQuery } from "mongoose";

export class FavouritesAdapterMongoose implements IFavouritesAdapter {
    schema: Schema;
    favouritesList: Model<IFavouriteDocument>;

    constructor() {
        this.schema = new Schema({
            userId: {
                type: Schema.Types.ObjectId,
                required: true,
                ref: "User",
            },
            serviceId: {
                type: Schema.Types.ObjectId,
                required: true,
                ref: "Service",
            },
            createdAt: { type: Date, default: Date.now, required: true },
        });

        this.favouritesList = model<IFavouriteDocument>("Favourite", this.schema);
    }

    public async create(data: Omit<CreateFavouriteParams, "sessionUser">): Promise<IFavourite> {
        return await this.favouritesList.create(data);
    }

    public async delete(data: Omit<DeleteFavouriteParams, "sessionUser">): Promise<void> {
        await this.favouritesList.deleteOne({ _id: data.id });
    }

    public async find(filters: Omit<FindFavouritesParams, "sessionUser">): Promise<IFavourite[]> {
        const searchCriteria = this.buildSearchCriteria(filters);
        return await this.favouritesList.find(searchCriteria).exec();
    }

    public async findOne(
        filters: Omit<FindFavouritesParams, "sessionUser">
    ): Promise<IFavouriteDocument | null> {
        const searchCriteria = this.buildSearchCriteria(filters);
        return await this.favouritesList.findOne(searchCriteria).exec();
    }

        private buildSearchCriteria(
        filters: Omit<FindFavouritesParams, "sessionUser">
    ): FilterQuery<IFavourite> {
        const searchCriteria: FilterQuery<IFavourite> = {};

        if (filters.id) searchCriteria._id = filters.id;
        if (filters.userId) searchCriteria.userId = filters.userId;
        if (filters.serviceId) searchCriteria.serviceId = filters.serviceId;

        if (filters.startDate && filters.endDate) {
            searchCriteria.createdAt = {
                $gte: filters.startDate,
                $lte: filters.endDate,
            };
        }

        return searchCriteria;
    }

    public async paginate(filters: PaginateFavouritesParams): Promise<PaginateFavouritesResults> {
        const searchCriteria = this.buildSearchCriteria(filters);

        const count = await this.favouritesList.countDocuments(searchCriteria).exec();
        const skip = (filters.page - 1) * filters.limit;

        const results = await this.favouritesList
            .find(searchCriteria)
            .skip(skip)
            .limit(filters.limit)
            .sort({ createdAt: -1 })
            .exec();

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