/* eslint-disable @typescript-eslint/lines-between-class-members */
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
import type { LiteralUnion } from 'type-fest';

import { createIdGenerator } from '../../libs/util';
import type { SubscriptionSchedulePhase } from './types';

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

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

  declare livemode: boolean;

  declare current_phase: {
    end_date: Date;
    start_date: Date;
  };

  declare customer_id: string;
  declare subscription_id: string;

  declare metadata: Record<string, any>;

  declare status: LiteralUnion<'active' | 'canceled' | 'completed' | 'not_started' | 'released', string>;

  declare phases?: SubscriptionSchedulePhase[];

  // Object representing the subscription schedule’s default settings.
  declare default_settings?: {
    billing_cycle_anchor: LiteralUnion<'phase_start' | 'automatic', string>;
    billing_thresholds: {
      amount_gte: number;
      reset_billing_cycle_anchor: boolean;
    };
    collection_method: LiteralUnion<'charge_automatically' | 'send_invoice', string>;
    default_payment_method: string;
    description: string;
    invoice_settings: {
      days_until_due: number;
    };
    // TODO: following fields not supported
    // application_fee_percent?: number;
    // automatic_tax?: {
    //   enabled: boolean;
    // };
    // on_behalf_of?: string;
    // transfer_data?: any;
  };

  declare end_behavior: LiteralUnion<'cancel' | 'release', string>;

  declare released_subscription_id?: string;

  declare test_clock_id?: string;

  // TODO: following fields not supported
  // application

  declare canceled_at: number;
  declare completed_at: number;
  declare released_at: 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,
    },
    current_phase: {
      type: DataTypes.JSON,
      allowNull: false,
    },
    customer_id: {
      type: DataTypes.STRING(30),
      allowNull: false,
    },
    subscription_id: {
      type: DataTypes.STRING(30),
      allowNull: false,
    },
    released_subscription_id: {
      type: DataTypes.STRING(30),
      allowNull: true,
    },
    status: {
      type: DataTypes.ENUM('active', 'canceled', 'completed', 'not_started', 'released'),
      allowNull: false,
    },
    default_settings: {
      type: DataTypes.JSON,
      allowNull: true,
    },
    end_behavior: {
      type: DataTypes.ENUM('cancel', 'release'),
      allowNull: false,
    },
    test_clock_id: {
      type: DataTypes.STRING(30),
      allowNull: true,
    },
    metadata: {
      type: DataTypes.JSON,
      allowNull: true,
    },
    canceled_at: {
      type: DataTypes.INTEGER,
      allowNull: true,
    },
    completed_at: {
      type: DataTypes.INTEGER,
      allowNull: true,
    },
    released_at: {
      type: DataTypes.INTEGER,
      allowNull: true,
    },
    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(SubscriptionSchedule.GENESIS_ATTRIBUTES, {
      sequelize,
      modelName: 'SubscriptionSchedule',
      tableName: 'subscription_schedules',
      createdAt: 'created_at',
      updatedAt: 'updated_at',
    });
  }

  public static associate(models: any) {
    this.belongsTo(models.Subscription, {
      foreignKey: 'subscription_id',
      as: 'subscription',
    });
  }
}

export type TSubscriptionSchedule = InferAttributes<SubscriptionSchedule>;
