import { Document, Model, Schema, model } from "mongoose";
import { IMetrics, IMetricsAdapter, MetricsParams } from "./Metrics.Interface";
import dayjs from "dayjs";
import { isNull } from "../../helpers/IsNull";
export interface IMetricsDocument extends Omit<IMetrics, "id">, Document {}

export class MetricsAdapterMongoose implements IMetricsAdapter {
    schema: Schema;
    metricsList: Model<IMetricsDocument>;

    constructor() {
        this.schema = new Schema({
            userId: { type: Schema.Types.ObjectId, required: true, ref: "User" },
            organizationsCount: { type: Number, required: true },
            employeesCount: { type: Number, required: true },
            servicesCount: { type: Number, required: true },
            appointmentsCount: { type: Number, required: true },
            clientsCount: { type: Number, required: true },
            repeatsCount: { type: Number, required: false },
            month: { type: Number, required: true },
            year: { type: Number, required: true },
            creationDate: { type: Date, required: true, default: Date.now },
        });

        this.metricsList = model<IMetricsDocument>("Metric", this.schema);
    }

    private getDate(): { month: number; year: number } {
        const dateNow = dayjs(new Date());
        const month = dateNow.month();
        const year = dateNow.year();
        return { month, year };
    }

    public async create(userId: string): Promise<IMetricsDocument> {
        const { month, year } = this.getDate();
        return await this.metricsList.create({
            userId,
            month,
            year,
            organizationsCount: 0,
            employeesCount: 0,
            servicesCount: 0,
            appointmentsCount: 0,
            clientsCount: 0,
            repeatsCount: 0,
        });
    }

    public async reset(userId: string): Promise<IMetricsDocument> {
        const { month, year } = this.getDate();
        let metrics: IMetricsDocument | null = await this.metricsList.findOne({ userId });

        if (metrics) {
            metrics.appointmentsCount = 0;
            // metrics.organizationsCount = 0;
            // metrics.employeesCount = 0;
            // metrics.servicesCount = 0;
            // metrics.clientsCount = 0;
            // metrics.repeatsCount = 0;
            metrics.year = year;
            metrics.month = month;
            await metrics.save();
        }

        if (!metrics) {
            metrics = await this.create(userId);
        }

        return metrics;
    }

    public async getMetrics(userId: string): Promise<IMetricsDocument> {
        let metrics: IMetricsDocument | null = await this.metricsList.findOne({ userId });

        if (!metrics) {
            metrics = await this.create(userId);
        }

        return metrics;
    }

    public async addOrganization(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        metrics.organizationsCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }

    public async addEmployee(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        metrics.employeesCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }

    public async addService(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        metrics.servicesCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }

    public async addAppointment(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        metrics.appointmentsCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }

    public async addClient(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        metrics.clientsCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }

    public async addRepeat(data: MetricsParams): Promise<void> {
        const { month, year } = this.getDate();
        if (!data.userId) {
            return;
        }
        let metrics = await this.getMetrics(data.userId);
        if (metrics.year !== year || metrics.month !== month) {
            metrics = await this.reset(data.userId);
        }
        if (!metrics.repeatsCount) {
            metrics.repeatsCount = 0;
        }
        metrics.repeatsCount += isNull<number>(data.quantity, 1);
        await metrics.save();
    }
}
