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

import { BN } from '@ocap/util';
import { createIdGenerator } from '../../libs/util';
import { PaymentDetails, PaymentSettings } from './types';

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

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

  declare enabled: boolean;
  declare threshold: string;
  declare currency_id: string; // default credit currency id
  declare recharge_currency_id?: string; // payment currency id
  declare price_id: string;
  declare quantity: number;
  declare payment_method_id?: string;

  declare payment_settings?: PaymentSettings;

  declare payment_details?: PaymentDetails;

  declare daily_limits?: {
    max_attempts: number;
    max_amount: string;
  };

  declare last_recharge_date?: string;
  declare daily_stats?: {
    attempt_count: number;
    total_amount: string;
  };

  declare slippage_config?: {
    mode?: 'percent' | 'rate';
    percent?: number;
    min_acceptable_rate?: string;
    base_currency?: string;
    updated_at_ms?: number;
  } | null;

  declare metadata?: Record<string, any>;
  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,
    },
    customer_id: {
      type: DataTypes.STRING(18),
      allowNull: false,
      references: {
        model: 'customers',
        key: 'id',
      },
    },
    livemode: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
    },
    enabled: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: false,
    },
    threshold: {
      type: DataTypes.STRING(32),
      allowNull: false,
    },
    payment_method_id: {
      type: DataTypes.STRING(15),
      allowNull: true,
    },
    currency_id: {
      type: DataTypes.STRING(15),
      allowNull: false,
    },
    recharge_currency_id: {
      type: DataTypes.STRING(15),
      allowNull: true,
    },
    price_id: {
      type: DataTypes.STRING(32),
      allowNull: false,
    },
    quantity: {
      type: DataTypes.INTEGER,
      defaultValue: 1,
      allowNull: false,
    },
    payment_settings: {
      type: DataTypes.JSON,
      allowNull: true,
      defaultValue: {
        payment_method_types: [],
        payment_method_options: {},
      },
    },
    payment_details: {
      type: DataTypes.JSON,
      allowNull: true,
    },
    daily_limits: {
      type: DataTypes.JSON,
      allowNull: true,
      defaultValue: {
        max_attempts: 0,
        max_amount: '0',
      },
    },
    last_recharge_date: {
      type: DataTypes.STRING(10),
      allowNull: true,
    },
    daily_stats: {
      type: DataTypes.JSON,
      allowNull: false,
      defaultValue: {
        attempt_count: 0,
        total_amount: '0',
      },
    },
    slippage_config: {
      type: DataTypes.JSON,
      allowNull: true,
    },
    metadata: {
      type: DataTypes.JSON,
      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(AutoRechargeConfig.GENESIS_ATTRIBUTES, {
      sequelize,
      modelName: 'AutoRechargeConfig',
      tableName: 'auto_recharge_configs',
      createdAt: 'created_at',
      updatedAt: 'updated_at',
    });
  }

  public static associate(models: any) {
    this.belongsTo(models.Customer, {
      foreignKey: 'customer_id',
      as: 'customer',
    });

    this.belongsTo(models.PaymentCurrency, {
      foreignKey: 'currency_id',
      as: 'currency',
    });

    this.belongsTo(models.PaymentCurrency, {
      foreignKey: 'recharge_currency_id',
      as: 'rechargeCurrency',
    });

    this.belongsTo(models.Price, {
      foreignKey: 'price_id',
      as: 'price',
    });

    this.belongsTo(models.PaymentMethod, {
      foreignKey: 'payment_method_id',
      as: 'paymentMethod',
    });
  }

  public canRechargeToday(nextAmount: string): boolean {
    const today = new Date().toISOString().split('T')[0];

    if (this.last_recharge_date !== today) {
      return true;
    }

    if (!this.daily_stats || !this.daily_limits) {
      return true;
    }

    const attemptValid =
      Number(this.daily_limits.max_attempts) === 0 ||
      Number(this.daily_stats.attempt_count) < Number(this.daily_limits.max_attempts);
    const amountValid =
      new BN(this.daily_limits?.max_amount || '0').lte(new BN(0)) ||
      new BN(this.daily_stats.total_amount || '0')
        .add(new BN(nextAmount))
        .lte(new BN(this.daily_limits.max_amount || '0'));

    if (attemptValid && amountValid) {
      return true;
    }
    return false;
  }

  public async updateDailyStats(amount: string): Promise<void> {
    const today = new Date().toISOString().split('T')[0];

    if (this.last_recharge_date !== today) {
      await this.update({
        last_recharge_date: today,
        daily_stats: {
          attempt_count: 1,
          total_amount: amount,
        },
      });
    } else {
      await this.update({
        daily_stats: {
          attempt_count: (this.daily_stats?.attempt_count || 0) + 1,
          total_amount: new BN(this.daily_stats?.total_amount || '0').add(new BN(amount)).toString(),
        },
      });
    }
  }
}

export type TAutoRechargeConfig = InferAttributes<AutoRechargeConfig>;
