import dayjs from 'dayjs';
import { Op } from 'sequelize';

import type { SubscriptionWillRenewEmailTemplateOptions } from '../libs/notification/template/subscription-will-renew';
import { Subscription } from '../store/models';
import { BaseSubscriptionScheduleNotification, BaseSubscriptionScheduleNotificationEventType } from './base';
import type { Diff, Task } from './interface/base';

export class SubscriptionWillRenewSchedule extends BaseSubscriptionScheduleNotification<SubscriptionWillRenewEmailTemplateOptions> {
  override eventType: BaseSubscriptionScheduleNotificationEventType = 'customer.subscription.will_renew';

  async getSubscriptions(): Promise<Subscription[]> {
    const subscriptions = await Subscription.findAll({
      where: {
        // @note: 之所以除 1000,是因为时间的精确度是 s
        current_period_start: {
          [Op.lte]: this.start / 1000,
        },
        current_period_end: {
          [Op.lt]: this.end / 1000,
        },
        status: 'active',
      },
      attributes: ['id', 'current_period_start', 'current_period_end', 'status'],
      raw: true,
    });

    return subscriptions;
  }

  override getTask({
    subscription,
    diff,
  }: {
    subscription: Subscription;
    diff: Diff;
  }): Task<SubscriptionWillRenewEmailTemplateOptions> {
    const type = this.eventType;
    const periodEnd = this.getEndTime(subscription);
    if (periodEnd <= this.start) {
      throw new Error(`Subscription(${subscription.id}) is already expired, no need to send notification`);
    }
    if (subscription.status !== 'active') {
      throw new Error(`Subscription(${subscription.id}) is not active, no need to send notification`);
    }
    return {
      id: `${subscription.id}.${type}.${diff.value}.${diff.unit}`,
      job: {
        type,
        options: {
          subscriptionId: subscription.id,
          willRenewValue: diff.value,
          willRenewUnit: diff.unit,
          required: !!diff.required,
        },
      },
      delay: dayjs(periodEnd).subtract(diff.value, diff.unit).diff(this.start, 's'),
    };
  }

  override getEndTime(subscription: Subscription): number {
    return subscription.current_period_end * 1000;
  }
}
