import { CollectionGroup, GroupUser } from "@server/models";
import { Op, DataTypes, sequelize } from "../sequelize";

const Group = sequelize.define(
  "group",
  {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true,
    },
    teamId: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
    },
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    timestamps: true,
    paranoid: true,
    validate: {
      isUniqueNameInTeam: async function () {
        const foundItem = await Group.findOne({
          where: {
            teamId: this.teamId,
            name: {
              [Op.iLike]: this.name,
            },
            id: {
              [Op.not]: this.id,
            },
          },
        });

        if (foundItem) {
          throw new Error("The name of this group is already in use");
        }
      },
    },
  }
);

// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'models' implicitly has an 'any' type.
Group.associate = (models) => {
  Group.hasMany(models.GroupUser, {
    as: "groupMemberships",
    foreignKey: "groupId",
  });
  Group.hasMany(models.CollectionGroup, {
    as: "collectionGroupMemberships",
    foreignKey: "groupId",
  });
  Group.belongsTo(models.Team, {
    as: "team",
    foreignKey: "teamId",
  });
  Group.belongsTo(models.User, {
    as: "createdBy",
    foreignKey: "createdById",
  });
  Group.belongsToMany(models.User, {
    as: "users",
    through: models.GroupUser,
    foreignKey: "groupId",
  });
  Group.addScope("defaultScope", {
    include: [
      {
        association: "groupMemberships",
        required: false,
      },
    ],
    order: [["name", "ASC"]],
  });
};

// Cascade deletes to group and collection relations
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'group' implicitly has an 'any' type.
Group.addHook("afterDestroy", async (group, options) => {
  if (!group.deletedAt) return;
  await GroupUser.destroy({
    where: {
      groupId: group.id,
    },
  });
  await CollectionGroup.destroy({
    where: {
      groupId: group.id,
    },
  });
});

export default Group;
