import {
    FindWapServerParams,
    IWapServer,
    IWapServerAdapter,
    PaginateWapServerParams,
    PaginateWapServerResults,
} from "./WapServer.Interface";
import { Document, Model, Schema, model, FilterQuery } from "mongoose";

export interface IWapServerDocument extends Omit<IWapServer, "id">, Document {}

export class WapServerAdapterMongoose implements IWapServerAdapter {
    schema: Schema;
    serverList: Model<IWapServerDocument>;

    constructor() {
        this.schema = new Schema({
            name: { type: String, required: false },
            description: { type: String, required: false },
            ipv4: { type: String, required: true },
            ipv6: { type: String, required: false },
            countBots: { type: Number, required: true, default: 0 },
            maxBots: { type: Number, required: true, default: 20 },
            active: { type: Boolean, required: true, default: true },
            port: { type: Number, required: true, default: 3000 },
        });

        this.serverList = model<IWapServerDocument>("WapServer", this.schema);
    }

    public async find(data: FindWapServerParams): Promise<IWapServer[]> {
        return this.serverList.find(data).exec();
    }

    public async findOne(data: FindWapServerParams): Promise<IWapServerDocument | null> {
        return this.serverList.findOne(data).exec();
    }

    private buildSearchCriteria(filters: FindWapServerParams): FilterQuery<IWapServerDocument> {
        const searchCriteria: FilterQuery<IWapServerDocument> = {};

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

        if (filters.name) {
            searchCriteria.name = { $regex: filters.name, $options: "i" };
        }

        if (filters.description) {
            searchCriteria.description = { $regex: filters.description, $options: "i" };
        }

        if (filters.active !== undefined) {
            searchCriteria.active = filters.active;
        }

        if (filters.countBotsFrom) {
            searchCriteria.countBots = { $gte: filters.countBotsFrom };
        }

        if (filters.countBotsTo) {
            searchCriteria.countBots = { $lte: filters.countBotsTo };
        }

        return searchCriteria;
    }

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

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

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

        let pages = Math.ceil(count / filters.limit);
        if (pages == 0) {
            pages = 1;
        }

        return { data: results, page: filters.page, pages: pages };
    }
}
