import { Op } from 'sequelize';
import dayjs from 'dayjs';
import logger from '../../libs/logger';
import createQueue from '../../libs/queue';
import { CheckoutSession, Subscription } from '../../store/models';
import { vendorReturnProcessorQueue } from './return-processor';
import { VendorInfo } from './fulfillment-coordinator';
import { events } from '../../libs/event';

export const vendorReturnScannerQueue = createQueue({
  name: 'vendor-return-scanner',
  onJob: handleReturnScannerJob,
  options: {
    concurrency: 1,
    maxRetries: 3,
    retryDelay: 60 * 1000,
  },
});

async function handleReturnScannerJob(): Promise<void> {
  try {
    const sessionsNeedingReturn = await findSessionsNeedingVendorReturn();
    if (sessionsNeedingReturn.length === 0) {
      logger.info('No checkout sessions needing vendor return');
      return;
    }

    logger.info('Found checkout sessions needing vendor return', {
      count: sessionsNeedingReturn.length,
      sessionIds: sessionsNeedingReturn.map((s) => s.id),
    });

    for (const session of sessionsNeedingReturn) {
      const id = `vendor-return-process-${session.id}`;
      // eslint-disable-next-line no-await-in-loop
      const exists = await vendorReturnProcessorQueue.get(id);
      if (!exists) {
        vendorReturnProcessorQueue.push({
          id,
          job: {
            checkoutSessionId: session.id,
          },
        });
      }
    }
  } catch (error: any) {
    logger.error('Vendor return scanner job failed', {
      error,
    });
    throw error;
  }
}

async function findSessionsNeedingVendorReturn(): Promise<CheckoutSession[]> {
  try {
    // First, find canceled subscriptions
    const oneWeekAgo = dayjs().subtract(7, 'day').unix();

    const canceledSubscriptions = await Subscription.findAll({
      where: { status: 'canceled', canceled_at: { [Op.gt]: oneWeekAgo } },
      attributes: ['id'],
    });

    const canceledSubscriptionIds = canceledSubscriptions.map((sub) => sub.id);

    // Find checkout sessions with completed fulfillment and canceled subscriptions
    const readyToReturnSessions = await CheckoutSession.findAll({
      where: {
        fulfillment_status: { [Op.notIn]: ['returning', 'returned', 'failed'] },
        subscription_id: { [Op.in]: canceledSubscriptionIds },
        vendor_info: { [Op.not]: null as any },
      },
      order: [['updated_at', 'DESC']],
      limit: 100,
    });

    // Find checkout sessions already in returning status
    const returningSessions = await CheckoutSession.findAll({
      where: {
        fulfillment_status: 'returning',
        subscription_id: { [Op.ne]: null as any },
      },
      order: [['updated_at', 'DESC']],
      limit: 100,
    });

    // Update canceled sessions to returning status
    if (readyToReturnSessions.length > 0) {
      await CheckoutSession.update(
        {
          fulfillment_status: 'returning',
        },
        {
          where: {
            id: { [Op.in]: readyToReturnSessions.map((s) => s.id) },
          },
        }
      );
    }

    const sessions = [...readyToReturnSessions, ...returningSessions];

    // Filter sessions that have vendors needing return
    const filteredSessions = sessions.filter((session) => {
      const vendorInfoList = session.vendor_info as VendorInfo[];

      if (!vendorInfoList || vendorInfoList.length === 0) {
        return false;
      }

      const hasVendorNeedingReturn = vendorInfoList.some(
        (vendor) => !['cancelled', 'return_requested', 'returned'].includes(vendor.status)
      );
      return hasVendorNeedingReturn;
    });

    return filteredSessions;
  } catch (error: any) {
    logger.error('Failed to find sessions needing vendor return', { error });
    throw error;
  }
}

export function scheduleVendorReturnScan(): void {
  const scanId = `scan-${Date.now()}`;
  vendorReturnScannerQueue.push({ id: scanId, job: {} });
}

events.on('customer.subscription.deleted', async (subscription: Subscription) => {
  logger.info('Customer subscription deleted', { subscription });
  if (subscription.status !== 'canceled') {
    logger.info('Subscription is not canceled, skipping vendor return process[customer.subscription.deleted]', {
      subscriptionId: subscription.id,
    });
    return;
  }

  const session = await CheckoutSession.findOne({
    where: { subscription_id: subscription.id },
    attributes: ['id', 'vendor_info'],
  });

  const isVendor = session?.vendor_info && session.vendor_info.length > 0;

  if (session && isVendor) {
    const id = `vendor-return-process-${session.id}`;
    // eslint-disable-next-line no-await-in-loop
    const exists = await vendorReturnProcessorQueue.get(id);
    if (!exists) {
      vendorReturnProcessorQueue.push({
        id,
        job: {
          checkoutSessionId: session.id,
        },
      });
    }
  }
});
