import {
    FindClientsParams,
    IClientsAdapter,
    IClient,
    CreateCustomClientParams,
    CreateClientByUserParams,
    PaginateClientsParams,
    PaginateClientsResults,
} from "./Clients.Interface";
import { Document, FilterQuery, Model, Schema, model } from "mongoose";

export interface IClientDocument extends Omit<IClient, "id">, Document {}

export class ClientsAdapterMongoose implements IClientsAdapter {
    schema: Schema;
    clientList: Model<IClientDocument>;

    constructor() {
        this.schema = new Schema({
            userId: { type: Schema.Types.ObjectId, required: false, ref: "User" },
            companyId: { type: Schema.Types.ObjectId, required: true, ref: "Companie" },
            fromClientId: { type: String, required: false, default: undefined },
            status: { type: Boolean, required: true, default: true },
            firstName: { type: String, required: false, default: undefined },
            lastName: { type: String, required: false, default: undefined },
            phoneNumber: { type: String, required: false, default: undefined },
            phoneCountryCode: { type: String, required: false, default: undefined },
            phoneAreaCode: { type: String, required: false, default: undefined },
            email: { type: String, required: true, default: undefined },
            creationDate: { type: Date, required: true, default: Date.now },
            banned: { type: Boolean, required: false, default: false },
        });

        this.clientList = model<IClientDocument>("Client", this.schema);
    }

    public async create(
        data: CreateClientByUserParams | CreateCustomClientParams
    ): Promise<IClientDocument> {
        return await this.clientList.create(data);
    }

    public async delete(id: string): Promise<void> {
        await this.clientList.deleteOne({ _id: id });
    }

    public async find(filters: FindClientsParams): Promise<IClient[]> {
        return this.clientList.find(filters).exec();
    }

    public async findOne(filters: FindClientsParams): Promise<IClientDocument | null> {
        return this.clientList.findOne(filters).exec();
    }

    public async paginate(filters: PaginateClientsParams): Promise<PaginateClientsResults> {
        const { page, limit, ...findFilters } = filters; //Extract page and limit from filters

        const newFilter: FilterQuery<IClientDocument> = {};

        if (findFilters.firstName) {
            newFilter.firstName = { $regex: findFilters.firstName, $options: "i" };
        }

        if (findFilters.lastName) {
            newFilter.lastName = { $regex: findFilters.lastName, $options: "i" };
        }

        if (findFilters.email) {
            newFilter.email = { $regex: findFilters.email, $options: "i" };
        }

        if (findFilters.companyId) {
            newFilter.companyId = findFilters.companyId;
        }

        if (findFilters.userId) {
            newFilter.userId = findFilters.userId;
        }

        if (findFilters.status) {
            newFilter.status = findFilters.status;
        }

        const count = await this.clientList.countDocuments(newFilter).exec();
        const skip = (page - 1) * limit;

        const results = await this.clientList
            .find(newFilter)
            .skip(skip)
            .limit(filters.limit)
            .exec();

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