/* eslint-disable no-console */
import dayjs from 'dayjs';

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

export class SubscriptionWillCanceledSchedule extends BaseSubscriptionScheduleNotification<SubscriptionWillCanceledEmailTemplateOptions> {
  override eventType: BaseSubscriptionScheduleNotificationEventType = 'customer.subscription.will_canceled';

  async getSubscriptions(): Promise<Subscription[]> {
    const subscriptions = await Subscription.findAll({
      where: {
        status: ['active', 'past_due'],
        [Op.or]: [
          { cancel_at: { [Op.gt]: this.start } },
          { cancel_at_period_end: true, current_period_end: { [Op.gt]: this.start } },
        ],
      },
      attributes: ['id', 'current_period_start', 'current_period_end', 'cancel_at', 'status'],
      raw: true,
    });

    subscriptions.forEach((subscription) => {
      if (subscription.cancel_at) {
        subscription.current_period_end = subscription.cancel_at;
      }
    });

    return subscriptions;
  }

  override getTask({
    subscription,
    diff,
  }: {
    subscription: Subscription;
    diff: Diff;
  }): Task<SubscriptionWillCanceledEmailTemplateOptions> {
    const type = this.eventType;
    const cancelAt = this.getEndTime(subscription);
    if (!cancelAt) {
      throw new Error(`Subscription(${subscription.id}) has no cancel_at, no need to send notification`);
    }
    if (cancelAt <= this.start) {
      throw new Error(`Subscription(${subscription.id}) is already canceled, no need to send notification`);
    }
    return {
      id: `${subscription.id}.${type}.${diff.value}.${diff.unit}`,
      job: {
        type,
        options: {
          subscriptionId: subscription.id,
          willCancelValue: diff.value,
          willCancelUnit: diff.unit,
          required: true,
        },
      },
      delay: dayjs(cancelAt).subtract(diff.value, diff.unit).diff(this.start, 's'),
    };
  }

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