import {
    FindEmployeesServicesParams,
    IEmployeesServicesAdapter,
    IEmployeeService,
    CreateEmployeeServiceParams,
    UpdateEmployeeServiceParams,
    PaginateEmployeesServicesParams,
    PaginateEmployeesServicesResults,
} from "./EmployeesServices.Interface";
import { Document, Model, Schema, model } from "mongoose";

export interface IEmployeeServiceDocument extends Omit<IEmployeeService, "id">, Document {}

export class EmployeesServicesAdapterMongoose implements IEmployeesServicesAdapter {
    schema: Schema;
    employeesServicesList: Model<IEmployeeServiceDocument>;

    constructor() {
        this.schema = new Schema({
            serviceId: { type: Schema.Types.ObjectId, required: true, ref: "Service" },
            employeeId: { type: Schema.Types.ObjectId, required: true, ref: "Employee" },
            companyId: { type: Schema.Types.ObjectId, required: true, ref: "Companie" },
            price: { type: Number, required: false },
            creationDate: { type: Date, required: true, default: Date.now },
        });

        this.employeesServicesList = model<IEmployeeServiceDocument>(
            "EmployeeService",
            this.schema
        );
    }

    public async create(data: CreateEmployeeServiceParams): Promise<IEmployeeService> {
        return await this.employeesServicesList.create(data);
    }

    public async update(data: UpdateEmployeeServiceParams): Promise<void> {
        const updateEmployeeService = await this.employeesServicesList.findOne({ _id: data.id });

        if (!updateEmployeeService) {
            throw new Error("Employee service not found");
        }

        if (data.price) {
            updateEmployeeService.price = data.price;
        }

        await updateEmployeeService.save();
    }

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

    public async find(filters: FindEmployeesServicesParams): Promise<IEmployeeService[]> {
        return this.employeesServicesList.find(filters).exec();
    }

    public async findOne(
        filters: FindEmployeesServicesParams
    ): Promise<IEmployeeServiceDocument | null> {
        return this.employeesServicesList.findOne(filters).exec();
    }

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

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

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