/* Disabled due to sequelize's DataTypes */
/* eslint-disable new-cap */

import type { Snowflake } from "discord.js";
import { Model, DataTypes, Op, type Sequelize } from "sequelize";
import { v4 as uuidv4 } from "uuid";
import log from "../../utils/logger";

export type OneBasedMonth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export function isOneBasedMonth(v: unknown): v is OneBasedMonth {
    return typeof v === "number"
    && Number.isInteger(v)
    && v >= 1
    && v <= 12;
}

export default class Birthday extends Model {
    declare id: string;
    declare userId: Snowflake;
    declare day: number;
    declare month: OneBasedMonth;

    static async insertBirthday(userId: Snowflake, day: number, month: OneBasedMonth) {
        const isoBirthdayStr = month.toString().padStart(2, "0") + "-" + day.toString().padStart(2, "0");

        log.debug(`Inserting Birthday for user ${userId} on YYYY-${isoBirthdayStr} (YYYY-MM-DD)`);

        const item = await Birthday.getBirthday(userId);

        if(item !== null) throw new Error("Birthday for this user already exists");

        return Birthday.create({
            userId,
            day,
            month
        });
    }

    static async getBirthday(userId: Snowflake) {
        return Birthday.findOne({
            where: { userId }
        });
    }

    static async getTodaysBirthdays() {
        const today = new Date(); // TODO: Rewrite to Temporal API after it is available
        const zeroBasedMonth = today.getMonth();
        return Birthday.findAll({
            where: {
                day: {
                    [Op.eq]: today.getDate()
                },
                month: {
                    [Op.eq]: zeroBasedMonth + 1
                }
            }
        });
    }

    static initialize(sequelize: Sequelize) {
        this.init({
            id: {
                type: DataTypes.STRING(36),
                defaultValue: () => uuidv4(),
                primaryKey: true
            },
            userId: {
                type: DataTypes.STRING(32),
                allowNull: false,
                unique: true
            },
            day: {
                type: DataTypes.INTEGER,
                allowNull: false,
                validate: {
                    min: 1,
                    max: 31
                }
            },
            month: {
                type: DataTypes.INTEGER,
                allowNull: false,
                validate: {
                    min: 1,
                    max: 12
                }
            }
        },
        {
            sequelize,
            modelName: "Birthday"
        });
    }
}