import Cron from '@abtnode/cron';

import { checkStakeRevokeTx } from '../integrations/arcblock/stake';
import {
  batchHandleStripeInvoices,
  batchHandleStripePayments,
  batchHandleStripeSubscriptions,
} from '../integrations/stripe/resource';
import {
  creditConsumptionCronTime,
  depositVaultCronTime,
  expiredSessionCleanupCronTime,
  notificationCronTime,
  overdueDetectionCronTime,
  paymentStatCronTime,
  revokeStakeCronTime,
  stripeInvoiceCronTime,
  stripePaymentCronTime,
  stripeSubscriptionCronTime,
  subscriptionCronTime,
  vendorStatusCheckCronTime,
  vendorReturnScanCronTime,
} from '../libs/env';
import logger from '../libs/logger';
import { startCreditConsumeQueue } from '../queues/credit-consume';
import { startDepositVaultQueue } from '../queues/payment';
import { startSubscriptionQueue } from '../queues/subscription';
import { startVendorStatusCheckSchedule } from '../queues/vendors/status-check';
import { CheckoutSession } from '../store/models';
import { createOverdueDetection } from './overdue-detection';
import { createPaymentStat } from './payment-stat';
import { SubscriptionTrialWillEndSchedule } from './subscription-trial-will-end';
import { SubscriptionWillCanceledSchedule } from './subscription-will-canceled';
import { SubscriptionWillRenewSchedule } from './subscription-will-renew';
import { scheduleVendorReturnScan } from '../queues/vendors/return-scanner';
import { getRetentionConfig } from '../libs/archive/config';
import { recoverFromCrash } from '../libs/archive/executor';
import { enqueueArchiveJob } from '../queues/archive';

function init() {
  // Recover any stale archive jobs from previous crash/restart
  recoverFromCrash().catch((error) => {
    logger.error('archive crash recovery error during init', { error });
  });

  const retentionConfig = getRetentionConfig();
  const archiveJobs =
    retentionConfig.enabled && retentionConfig.schedule.enabled
      ? [
          {
            name: 'data.retention.archive',
            time: retentionConfig.schedule.cron,
            fn: () =>
              enqueueArchiveJob({
                triggeredBy: 'cron',
              }),
            options: { runOnInit: false },
          },
        ]
      : [];
  Cron.init({
    context: {},
    jobs: [
      {
        name: 'subscription.will.renew',
        time: notificationCronTime,
        fn: () => new SubscriptionWillRenewSchedule().run(),
        options: { runOnInit: true },
      },
      {
        name: 'subscription.trial.will.end',
        time: notificationCronTime,
        fn: () => new SubscriptionTrialWillEndSchedule().run(),
        options: { runOnInit: true },
      },
      {
        name: 'customer.subscription.will_canceled',
        time: notificationCronTime,
        fn: () => new SubscriptionWillCanceledSchedule().run(),
        options: { runOnInit: true },
      },
      {
        name: 'subscription.schedule.retry',
        time: subscriptionCronTime,
        fn: startSubscriptionQueue,
        options: { runOnInit: false },
      },
      {
        name: 'checkoutSession.cleanup.expired',
        time: expiredSessionCleanupCronTime,
        fn: async () => {
          const removedCount = await CheckoutSession.cleanupExpiredSessions();
          logger.info('CheckoutSession.cleanupExpiredSessions', { removedCount });
        },
        options: { runOnInit: true },
      },
      {
        name: 'stripe.invoice.sync',
        time: stripeInvoiceCronTime,
        fn: batchHandleStripeInvoices,
        options: { runOnInit: false },
      },
      {
        name: 'stripe.payment.sync',
        time: stripePaymentCronTime,
        fn: batchHandleStripePayments,
        options: { runOnInit: false },
      },
      {
        name: 'stripe.subscription.sync',
        time: stripeSubscriptionCronTime,
        fn: batchHandleStripeSubscriptions,
        options: { runOnInit: false },
      },
      {
        name: 'customer.stake.revoked',
        time: revokeStakeCronTime,
        fn: checkStakeRevokeTx,
        options: { runOnInit: false },
      },
      {
        name: 'payment.stat',
        time: paymentStatCronTime,
        fn: () => createPaymentStat(),
        options: { runOnInit: false },
      },
      {
        name: 'payment.daily.report',
        time: overdueDetectionCronTime,
        fn: () => createOverdueDetection(),
        options: { runOnInit: false },
      },
      {
        name: 'deposit.vault',
        time: depositVaultCronTime,
        fn: () => startDepositVaultQueue(),
        options: { runOnInit: true },
      },
      {
        name: 'credit.consumption',
        time: creditConsumptionCronTime,
        fn: () => startCreditConsumeQueue(),
        options: { runOnInit: true },
      },
      {
        name: 'vendor.status.check',
        time: vendorStatusCheckCronTime,
        fn: () => startVendorStatusCheckSchedule(),
        options: { runOnInit: false },
      },
      {
        name: 'vendor.return.scan',
        time: vendorReturnScanCronTime,
        fn: () => scheduleVendorReturnScan(),
        options: { runOnInit: false },
      },
      ...archiveJobs,
    ],
    onError: (error: Error, name: string) => {
      logger.error('run job failed', { name, error });
    },
  });
}

export default {
  init,
};
