import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
import type { LiteralUnion } from 'type-fest';

import { createIdGenerator } from '../../libs/util';

const nextId = createIdGenerator('wa', 24);

// eslint-disable-next-line prettier/prettier
export class WebhookAttempt extends Model<InferAttributes<WebhookAttempt>, InferCreationAttributes<WebhookAttempt>> {
  declare id: CreationOptional<string>;
  declare livemode: boolean;

  declare event_id: string;
  declare webhook_endpoint_id: string;

  declare status: LiteralUnion<'succeeded' | 'failed', string>;
  declare response_status: number;
  declare response_body: any;

  declare retry_count: number;

  declare created_at: CreationOptional<Date>;
  declare updated_at: CreationOptional<Date>;

  public static readonly GENESIS_ATTRIBUTES = {
    id: {
      type: DataTypes.STRING(30),
      primaryKey: true,
      allowNull: false,
      defaultValue: nextId,
    },
    livemode: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
    },
    event_id: {
      type: DataTypes.STRING(30),
      allowNull: false,
    },
    webhook_endpoint_id: {
      type: DataTypes.STRING(30),
      allowNull: false,
    },
    status: {
      type: DataTypes.ENUM('succeeded', 'failed'),
      allowNull: false,
    },
    response_status: {
      type: DataTypes.INTEGER,
      allowNull: false,
    },
    response_body: {
      type: DataTypes.JSON,
      allowNull: false,
    },
    retry_count: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
    },
    created_at: {
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      allowNull: false,
    },
    updated_at: {
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      allowNull: false,
    },
  };

  public static initialize(sequelize: any) {
    this.init(WebhookAttempt.GENESIS_ATTRIBUTES, {
      sequelize,
      modelName: 'WebhookAttempt',
      tableName: 'webhook_attempts',
      createdAt: 'created_at',
      updatedAt: 'updated_at',
    });
  }

  public static associate(models: any) {
    this.hasOne(models.WebhookEndpoint, {
      sourceKey: 'webhook_endpoint_id',
      foreignKey: 'id',
      as: 'endpoint',
    });
    this.hasOne(models.Event, {
      sourceKey: 'event_id',
      foreignKey: 'id',
      as: 'event',
    });
  }
}

export type TWebhookAttempt = InferAttributes<WebhookAttempt>;
