import {
    FindAppointmentsParams,
    IAppointmentsAdapter,
    IAppointment,
    CreateAppointmentParams,
    PaginateAppointmentsParams,
    PaginateAppointmentsResults,
} from "./Appointments.Interface";
import { Document, Model, Schema, model } from "mongoose";

export interface IAppointmentDocument extends Omit<IAppointment, "id">, Document {}

export class AppointmentsAdapterMongoose implements IAppointmentsAdapter {
    schema: Schema;
    AppointmentList: Model<IAppointmentDocument>;

    constructor() {
        this.schema = new Schema({
            companyId: { type: Schema.Types.ObjectId, required: true, ref: "Companie" },
            serviceId: { type: Schema.Types.ObjectId, required: true, ref: "Service" },
            employeeId: { type: Schema.Types.ObjectId, required: true, ref: "Employee" },
            clientId: { type: Schema.Types.ObjectId, required: true, ref: "Client" },
            userId: { type: Schema.Types.ObjectId, required: false, ref: "User" },
            discountId: { type: Schema.Types.ObjectId, required: false, ref: "Discount" },
            start: { type: Date, required: true },
            startHour: { type: Number, required: true, default: 0 },
            endHour: { type: Number, required: true },
            dateDay: { type: Date, required: true },
            price: { type: Number, required: true, default: 0 },
            length: { type: Number, required: true, default: 0 },
            present: { type: Boolean, required: true, default: true },
            payment: { type: Boolean, required: true, default: false },
            comments: { type: String, required: false, default: "" },
            creationDate: { type: Date, required: true, default: Date.now },
        });

        this.AppointmentList = model<IAppointmentDocument>("Appointment", this.schema);
    }

    public async create(data: CreateAppointmentParams): Promise<IAppointment> {
        return await this.AppointmentList.create(data);
    }

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

    public async findByDateRange(
        startDate: Date,
        endDate: Date,
        companyId: string
    ): Promise<IAppointment[]> {
        return this.AppointmentList.find({
            dateDay: { $gte: startDate, $lte: endDate },
            companyId: companyId,
        }).exec();
    }

    public async find(filters: FindAppointmentsParams): Promise<IAppointment[]> {
        return this.AppointmentList.find(filters).exec();
    }

    public async findOne(filters: FindAppointmentsParams): Promise<IAppointmentDocument | null> {
        return this.AppointmentList.findOne(filters).exec();
    }

    public async paginate(
        filters: PaginateAppointmentsParams
    ): Promise<PaginateAppointmentsResults> {
        const { page, limit, ...findFilters } = filters; //Extract page and limit from filters
        const count = await this.AppointmentList.countDocuments(findFilters).exec();
        const skip = (page - 1) * limit;

        const results = await this.AppointmentList.find(findFilters)
            .skip(skip)
            .limit(filters.limit)
            .exec();

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