import * as Sequelize from "sequelize";
import { DataTypes, Model } from "sequelize";
import ecommerceProduct from "./ecommerceProduct";
import ecommerceUserDiscount from "./ecommerceUserDiscount";

export default class ecommerceDiscount
  extends Model<
    ecommerceDiscountAttributes,
    ecommerceDiscountCreationAttributes
  >
  implements ecommerceDiscountAttributes
{
  id!: string;
  code!: string;
  type!: "PERCENTAGE" | "FIXED" | "FREE_SHIPPING";
  percentage!: number;
  amount!: number;
  maxUses!: number;
  validFrom!: Date;
  validUntil!: Date;
  productId!: string;
  status!: boolean;
  createdAt?: Date;
  deletedAt?: Date;
  updatedAt?: Date;

  // ecommerceDiscount hasMany ecommerceUserDiscount via discountId
  ecommerceUserDiscounts!: ecommerceUserDiscount[];
  getEcommerceUserDiscounts!: Sequelize.HasManyGetAssociationsMixin<ecommerceUserDiscount>;
  setEcommerceUserDiscounts!: Sequelize.HasManySetAssociationsMixin<
    ecommerceUserDiscount,
    string
  >;
  addEcommerceUserDiscount!: Sequelize.HasManyAddAssociationMixin<
    ecommerceUserDiscount,
    string
  >;
  addEcommerceUserDiscounts!: Sequelize.HasManyAddAssociationsMixin<
    ecommerceUserDiscount,
    string
  >;
  createEcommerceUserDiscount!: Sequelize.HasManyCreateAssociationMixin<ecommerceUserDiscount>;
  removeEcommerceUserDiscount!: Sequelize.HasManyRemoveAssociationMixin<
    ecommerceUserDiscount,
    string
  >;
  removeEcommerceUserDiscounts!: Sequelize.HasManyRemoveAssociationsMixin<
    ecommerceUserDiscount,
    string
  >;
  hasEcommerceUserDiscount!: Sequelize.HasManyHasAssociationMixin<
    ecommerceUserDiscount,
    string
  >;
  hasEcommerceUserDiscounts!: Sequelize.HasManyHasAssociationsMixin<
    ecommerceUserDiscount,
    string
  >;
  countEcommerceUserDiscounts!: Sequelize.HasManyCountAssociationsMixin;
  // ecommerceDiscount belongsTo ecommerceProduct via productId
  product!: ecommerceProduct;
  getProduct!: Sequelize.BelongsToGetAssociationMixin<ecommerceProduct>;
  setProduct!: Sequelize.BelongsToSetAssociationMixin<
    ecommerceProduct,
    string
  >;
  createProduct!: Sequelize.BelongsToCreateAssociationMixin<ecommerceProduct>;

  public static initModel(sequelize: Sequelize.Sequelize): typeof ecommerceDiscount {
    return ecommerceDiscount.init(
      {
        id: {
          type: DataTypes.UUID,
          defaultValue: DataTypes.UUIDV4,
          primaryKey: true,
          allowNull: false,
        },
        code: {
          type: DataTypes.STRING(191),
          allowNull: false,
          unique: "ecommerceDiscountCodeKey",
          validate: {
            notEmpty: { msg: "code: Code must not be empty" },
          },
        },
        type: {
          type: DataTypes.ENUM("PERCENTAGE", "FIXED", "FREE_SHIPPING"),
          allowNull: false,
          defaultValue: "PERCENTAGE",
          validate: {
            isIn: {
              args: [["PERCENTAGE", "FIXED", "FREE_SHIPPING"]],
              msg: "type: Must be 'PERCENTAGE', 'FIXED', or 'FREE_SHIPPING'",
            },
          },
        },
        percentage: {
          type: DataTypes.INTEGER,
          allowNull: true,
          defaultValue: 0,
          validate: {
            isInt: { msg: "percentage: Percentage must be an integer" },
            min: {
              args: [0],
              msg: "percentage: Percentage cannot be negative",
            },
            max: {
              args: [100],
              msg: "percentage: Percentage cannot be more than 100",
            },
          },
        },
        amount: {
          type: DataTypes.DOUBLE,
          allowNull: true,
          defaultValue: 0,
          validate: {
            isFloat: { msg: "amount: Amount must be a valid number" },
            min: {
              args: [0],
              msg: "amount: Amount cannot be negative",
            },
          },
        },
        maxUses: {
          type: DataTypes.INTEGER,
          allowNull: true,
          validate: {
            isInt: { msg: "maxUses: Max uses must be an integer" },
            min: {
              args: [1],
              msg: "maxUses: Max uses must be at least 1",
            },
          },
        },
        validFrom: {
          type: DataTypes.DATE(3),
          allowNull: true,
          validate: {
            isDate: {
              msg: "validFrom: Must be a valid date",
              args: true,
            },
          },
        },
        validUntil: {
          type: DataTypes.DATE(3),
          allowNull: false,
          validate: {
            isDate: {
              msg: "validUntil: Must be a valid date",
              args: true,
            },
            // BUG-10: Use custom validator so it checks against current time, not server start time
            isFutureDate(value: string) {
              if (new Date(value) <= new Date()) {
                throw new Error("validUntil: Date must be in the future");
              }
            },
          },
        },
        productId: {
          type: DataTypes.UUID,
          allowNull: false,

          validate: {
            isUUID: {
              args: 4,
              msg: "productId: Product ID must be a valid UUID",
            },
          },
        },
        status: {
          type: DataTypes.BOOLEAN,
          allowNull: false,
          defaultValue: true,
          validate: {
            isBoolean: { msg: "status: Status must be a boolean value" },
          },
        },
      },
      {
        sequelize,
        modelName: "ecommerceDiscount",
        tableName: "ecommerce_discount",
        timestamps: true,
        paranoid: true,
        indexes: [
          {
            name: "PRIMARY",
            unique: true,
            using: "BTREE",
            fields: [{ name: "id" }],
          },
          {
            name: "ecommerceDiscountCodeKey",
            unique: true,
            using: "BTREE",
            fields: [{ name: "code" }],
          },
          {
            name: "ecommerceDiscountProductIdFkey",
            using: "BTREE",
            fields: [{ name: "productId" }],
          },
        ],
      }
    );
  }
  public static associate(models: any) {
    ecommerceDiscount.belongsTo(models.ecommerceProduct, {
      as: "product",
      foreignKey: "productId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
    ecommerceDiscount.hasMany(models.ecommerceUserDiscount, {
      as: "ecommerceUserDiscounts",
      foreignKey: "discountId",
      onDelete: "CASCADE",
      onUpdate: "CASCADE",
    });
  }
}
