import { BN } from '@ocap/util';
import { Op } from 'sequelize';
import { events } from '../../libs/event';
import { getLock } from '../../libs/lock';
import logger from '../../libs/logger';
import createQueue from '../../libs/queue';
import dayjs from '../../libs/dayjs';
import { VendorFulfillmentService } from '../../libs/vendor-util/fulfillment';
import { CheckoutSession } from '../../store/models/checkout-session';
import { PaymentIntent } from '../../store/models/payment-intent';
import { Price } from '../../store/models/price';
import { Product } from '../../store/models/product';
import { Refund } from '../../store/models/refund';
import { Subscription } from '../../store/models/subscription';
import { sequelize } from '../../store/sequelize';
import { depositVaultQueue } from '../payment';
import { addSubscriptionJob } from '../subscription';
import { SubscriptionWillCanceledSchedule } from '../../crons/subscription-will-canceled';
import { Invoice } from '../../store/models';

export type VendorInfo = NonNullable<CheckoutSession['vendor_info']>[number];

interface CoordinatorJob {
  checkoutSessionId: string;
  invoiceId: string;
  triggeredBy: string;
}

const MAX_FULFILLMENT_TIMEOUT = 300000;

// Helper function to get order info for coordinated fulfillment
async function getCoordinatedOrderInfo(checkoutSessionId: string) {
  const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId);

  if (!checkoutSession) {
    throw new Error('CheckoutSession or Invoice not found');
  }

  return {
    checkoutSessionId,
    amount_total: checkoutSession.amount_total,
    customer_id: checkoutSession.customer_id || '',
    invoiceId: checkoutSession.invoice_id || '',
    currency_id: checkoutSession.currency_id,
    customer_did: checkoutSession.customer_did || '',
  };
}

async function handleCoordinatedFulfillment(job: any): Promise<void> {
  const { checkoutSessionId, invoiceId, didnamesVendorConfig, launcherVendorConfig, context } = job;

  try {
    logger.info('Starting coordinated fulfillment', {
      checkoutSessionId,
      didnamesVendorId: didnamesVendorConfig.vendor_id,
      launcherVendorId: launcherVendorConfig.vendor_id,
    });

    const orderInfo = await getCoordinatedOrderInfo(checkoutSessionId);
    if (!orderInfo) {
      throw new Error('Order info not found');
    }

    // Step 1: Execute didnames fulfillment to generate bindDomainCap
    logger.info('Step 1: Executing didnames fulfillment', { checkoutSessionId });
    const didnamesResult = await VendorFulfillmentService.fulfillSingleVendorOrder(
      orderInfo,
      didnamesVendorConfig,
      context
    );

    if (didnamesResult.status === 'failed') {
      throw new Error(`Didnames fulfillment failed: ${didnamesResult.errorMessage}`);
    }

    // Extract bindDomainCap from didnames result
    const bindCapData = didnamesResult.orderDetails?.customParams || {};
    const { domain, sessionId, bindDomainCap, nftDid } = bindCapData;

    if (!bindDomainCap || !domain || !sessionId) {
      logger.warn('Missing bindDomainCap data from didnames adapter', {
        checkoutSessionId,
        hasBindCap: !!bindDomainCap,
        hasDomain: !!domain,
        hasSessionId: !!sessionId,
      });
    }

    // Update didnames vendor status
    await updateVendorFulfillmentStatus(
      checkoutSessionId,
      invoiceId,
      didnamesVendorConfig.vendor_id,
      didnamesResult.status === 'completed' ? 'completed' : 'sent',
      {
        orderId: didnamesResult.orderId,
        commissionAmount: didnamesResult.commissionAmount,
        serviceUrl: didnamesResult.serviceUrl,
      }
    );

    // Step 2: Execute launcher fulfillment with bindDomainCap
    logger.info('Step 2: Executing launcher fulfillment with bindDomainCap', {
      checkoutSessionId,
      hasBindCapData: !!bindDomainCap,
    });

    const launcherResult = await VendorFulfillmentService.fulfillSingleVendorOrder(orderInfo, launcherVendorConfig, {
      ...context,
      domain,
      sessionId,
      bindDomainCap,
      domainNftDid: nftDid,
    });

    // Update launcher vendor status
    await updateVendorFulfillmentStatus(
      checkoutSessionId,
      invoiceId,
      launcherVendorConfig.vendor_id,
      launcherResult.status === 'completed' ? 'completed' : 'sent',
      {
        orderId: launcherResult.orderId,
        commissionAmount: launcherResult.commissionAmount,
        serviceUrl: launcherResult.serviceUrl,
      }
    );

    logger.info('Coordinated fulfillment completed successfully', {
      checkoutSessionId,
      didnamesStatus: didnamesResult.status,
      launcherStatus: launcherResult.status,
    });

    // Check if all vendors are completed to trigger commission
    await triggerCommissionProcess(checkoutSessionId, invoiceId);
  } catch (error: any) {
    logger.error('Coordinated fulfillment failed', {
      checkoutSessionId,
      error: error.message,
    });

    // Mark both vendors as failed
    await updateVendorFulfillmentStatus(checkoutSessionId, invoiceId, didnamesVendorConfig.vendor_id, 'failed', {
      lastError: error.message,
    });

    await updateVendorFulfillmentStatus(checkoutSessionId, invoiceId, launcherVendorConfig.vendor_id, 'failed', {
      lastError: error.message,
    });

    throw error;
  }
}

export const fulfillmentCoordinatorQueue = createQueue({
  name: 'fulfillment-coordinator',
  onJob: handleFulfillmentCoordination,
});

export const coordinatedFulfillmentQueue = createQueue({
  name: 'coordinated-fulfillment',
  onJob: handleCoordinatedFulfillment,
  options: {
    concurrency: 1,
    maxRetries: 3,
    enableScheduledJob: true,
  },
});

export const startCoordinatedFulfillmentQueue = () => {
  logger.debug('startCoordinatedFulfillmentQueue');
  return Promise.resolve();
};

// Add event listener for coordinated fulfillment
events.on('vendor.fulfillment.coordinated', async (id, job) => {
  try {
    const exist = await coordinatedFulfillmentQueue.get(id);
    if (!exist) {
      logger.info('Adding coordinated fulfillment job to queue', { id, checkoutSessionId: job.checkoutSessionId });
      coordinatedFulfillmentQueue.push({
        id,
        job,
      });
    } else {
      logger.info('Coordinated fulfillment job already exists, skipping', { id });
    }
  } catch (error: any) {
    logger.error('Failed to handle coordinated fulfillment queue event', {
      id,
      error: error.message,
    });
  }
});

export async function startVendorFulfillment(checkoutSessionId: string, invoiceId: string): Promise<void> {
  try {
    logger.info('Starting vendor fulfillment process', {
      checkoutSessionId,
      invoiceId,
    });

    const vendorConfigs = await getVendorConfigurations(checkoutSessionId);

    // No vendor configuration → directly to cold wallets
    if (vendorConfigs.length === 0) {
      logger.info('No vendor configurations found, triggering commission directly', {
        checkoutSessionId,
      });

      await triggerCommissionProcess(checkoutSessionId, invoiceId);
      return;
    }

    const initialVendorInfo: VendorInfo[] = vendorConfigs.map((config) => ({
      vendor_id: config.vendor_id,
      vendor_key: config.vendor_key,
      vendor_type: config.vendor_type,
      name: config.name,
      order_id: '',
      status: 'pending' as 'pending',
      amount: config.amount || '0',
      attempts: 0,
      lastAttemptAt: new Date().toISOString(),
    }));

    await updateVendorInfo(checkoutSessionId, initialVendorInfo);

    // Check if we need coordinated fulfillment (didnames + launcher)
    const didnamesVendor = vendorConfigs.find((v) => v.vendor_type === 'didnames');
    const launcherVendor = vendorConfigs.find((v) => v.vendor_type === 'launcher');

    if (didnamesVendor && launcherVendor) {
      // Coordinated fulfillment: didnames first, then launcher with bindDomainCap
      logger.info('Starting coordinated domain binding fulfillment', {
        checkoutSessionId,
        invoiceId,
        didnamesVendorId: didnamesVendor.vendor_id,
        launcherVendorId: launcherVendor.vendor_id,
      });

      const coordinatedJobId = `coordinated-fulfillment-${checkoutSessionId}`;
      events.emit('vendor.fulfillment.coordinated', coordinatedJobId, {
        checkoutSessionId,
        invoiceId,
        didnamesVendorConfig: didnamesVendor,
        launcherVendorConfig: launcherVendor,
        retryOnError: true,
      });
    } else {
      // Regular parallel fulfillment for other vendors
      for (const vendorConfig of vendorConfigs) {
        const vendorFulfillmentJobId = `vendor-fulfillment-${checkoutSessionId}-${vendorConfig.vendor_id}`;

        events.emit('vendor.fulfillment.queued', vendorFulfillmentJobId, {
          checkoutSessionId,
          invoiceId,
          vendorId: vendorConfig.vendor_id,
          vendorConfig,
          retryOnError: true,
          context: {
            subdomain: `docsmith-${Date.now()}`,
          },
        });
      }
    }

    logger.info('Vendor fulfillment process has been triggered', {
      checkoutSessionId,
      invoiceId,
      vendorCount: vendorConfigs.length,
    });
  } catch (error: any) {
    logger.error('Failed to start vendor fulfillment', {
      checkoutSessionId,
      invoiceId,
      error: error.message,
    });
    throw error;
  }
}

export async function updateVendorFulfillmentStatus(
  checkoutSessionId: string,
  invoiceId: string,
  vendorId: string,
  result: 'completed' | 'failed' | 'max_retries_exceeded' | 'return_requested' | 'sent',
  details?: {
    orderId?: string;
    attempts?: number;
    lastError?: string;
    commissionAmount?: string;
    serviceUrl?: string;
  }
): Promise<void> {
  await updateSingleVendorInfo(checkoutSessionId, vendorId, {
    status: result,
    order_id: details?.orderId || '',
    attempts: details?.attempts || 0,
    error_message: details?.lastError,
    commissionAmount: details?.commissionAmount,
    service_url: details?.serviceUrl,
    completedAt: result === 'completed' ? new Date().toISOString() : undefined,
    lastAttemptAt: new Date().toISOString(),
  });

  await triggerCoordinatorCheck(checkoutSessionId, invoiceId, `vendor_${vendorId}_${result}`);
}

export async function handleFulfillmentCoordination(job: CoordinatorJob) {
  const { checkoutSessionId, invoiceId, triggeredBy } = job;

  logger.info('Processing fulfillment coordination', {
    checkoutSessionId,
    triggeredBy,
  });

  try {
    const vendorInfo = await getVendorInfo(checkoutSessionId);
    const vendorConfigs = await getVendorConfigurations(checkoutSessionId);

    if (vendorConfigs.length === 0) {
      logger.info('No vendors to coordinate, triggering commission directly', {
        checkoutSessionId,
      });
      await triggerCommissionProcess(checkoutSessionId, invoiceId);
      return;
    }

    const analysis = analyzeVendorStates(vendorInfo, vendorConfigs);

    logger.info('Vendor fulfillment analysis', {
      checkoutSessionId,
      analysis,
    });

    if (analysis.allCompleted) {
      logger.info('All vendors completed successfully, triggering commission', {
        checkoutSessionId,
        successfulVendors: analysis.successfulVendors.length,
      });

      await triggerCommissionProcess(checkoutSessionId, invoiceId);
    } else if (analysis.anyMaxRetriesExceeded || analysis.shouldTimeout || analysis.failedVendors.length > 0) {
      logger.warn('Some vendors failed, initiating full refund', {
        checkoutSessionId,
        failedVendors: analysis.failedVendors.length,
        maxRetriesExceededVendors: analysis.maxRetriesExceededVendors.length,
        timeoutVendors: analysis.shouldTimeout ? 'detected' : 'none',
      });

      await initiateFullRefund(invoiceId, 'vendor_failure_detected');
    } else {
      logger.info('Some vendors still in progress, waiting for completion', {
        checkoutSessionId,
        pendingVendors: analysis.pendingVendors.length,
        processingVendors: analysis.processingVendors.length,
        failedVendors: analysis.failedVendors.length,
      });
    }
  } catch (error: any) {
    logger.error('Fulfillment coordination failed', {
      checkoutSessionId,
      error: error.message,
    });

    await initiateFullRefund(invoiceId, 'coordination_failed');
  }
}

async function getVendorConfigurations(checkoutSessionId: string): Promise<any[]> {
  const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId);
  if (!checkoutSession?.line_items) {
    return [];
  }

  const priceIds = checkoutSession.line_items.map((item: any) => item.price_id).filter(Boolean);
  if (priceIds.length === 0) {
    return [];
  }

  const prices = await Price.findAll({
    where: { id: priceIds },
    attributes: ['id', 'product_id'],
  });

  const productIds = prices.map((price: any) => price.product_id).filter(Boolean);
  if (productIds.length === 0) {
    return [];
  }

  const product = await Product.findByPk(productIds[0]);
  return product?.vendor_config || [];
}

async function getVendorInfo(checkoutSessionId: string): Promise<VendorInfo[]> {
  const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId);
  return (checkoutSession?.vendor_info as VendorInfo[]) || [];
}

async function updateVendorInfo(checkoutSessionId: string, vendorInfo: VendorInfo[]): Promise<void> {
  await CheckoutSession.update({ vendor_info: vendorInfo }, { where: { id: checkoutSessionId } });
}

async function updateSingleVendorInfo(
  checkoutSessionId: string,
  vendorId: string,
  update: Partial<VendorInfo>
): Promise<void> {
  const lockKey = `vendor-info-${checkoutSessionId}`;

  logger.info('updateVendorInfo - Before update', {
    checkoutSessionId,
    vendorId,
    update,
    lockKey,
  });

  const lock = await getLock(lockKey);

  try {
    await sequelize.transaction(async (transaction: any) => {
      const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId, {
        transaction,
        lock: transaction.LOCK.UPDATE,
      });

      if (!checkoutSession) {
        throw new Error(`CheckoutSession not found: ${checkoutSessionId}`);
      }

      const current = (checkoutSession.vendor_info as VendorInfo[]) || [];
      const index = current.findIndex((vendor) => vendor.vendor_id === vendorId);

      if (index >= 0) {
        current[index] = {
          ...current[index],
          ...update,
          vendor_id: current[index]?.vendor_id || vendorId,
          order_id: update.order_id || current[index]?.order_id || '',
          status: update.status || current[index]?.status || 'pending',
          amount: update.commissionAmount || current[index]?.amount || '0',
        } as VendorInfo;
      } else {
        current.push({
          vendor_id: vendorId,
          order_id: update.order_id || '',
          status: update.status || 'pending',
          amount: update.commissionAmount || '0',
          ...update,
        } as VendorInfo);
      }

      logger.info('updateVendorInfo - After merge, before database update (in transaction)', {
        checkoutSessionId,
        vendorId,
        finalVendorInfo: current,
        updatedVendorStatus: index >= 0 ? current[index]?.status : current[current.length - 1]?.status,
      });

      const fulfillmentStatus =
        !checkoutSession.fulfillment_status ||
        !['completed', 'failed', 'cancelled', 'max_retries_exceeded', 'return_requested'].includes(
          checkoutSession.fulfillment_status
        )
          ? update.status
          : undefined;

      await CheckoutSession.update(
        {
          vendor_info: current,
          fulfillment_status: fulfillmentStatus,
        },
        {
          where: { id: checkoutSessionId },
          transaction,
        }
      );

      logger.info('updateVendorInfo - Database update completed (in transaction)', {
        checkoutSessionId,
        vendorId,
        updateStatus: update.status,
      });
    });
  } catch (error: any) {
    logger.error('updateVendorInfo - Update failed', {
      checkoutSessionId,
      vendorId,
      error,
    });
    throw error;
  } finally {
    lock.release();
    logger.info('updateVendorInfo - Lock released', {
      checkoutSessionId,
      vendorId,
      lockKey,
    });
  }
}

function analyzeVendorStates(vendorInfo: VendorInfo[], vendorConfigs: any[]) {
  const vendorIds = vendorConfigs.map((config) => config.vendor_id);

  const successfulVendors = vendorInfo.filter((vendor) => vendor.status === 'completed');
  const failedVendors = vendorInfo.filter((vendor) => vendor.status === 'failed');
  const maxRetriesExceededVendors = vendorInfo.filter((vendor) => vendor.status === 'max_retries_exceeded');
  const pendingVendors = vendorInfo.filter((vendor) => vendor.status === 'pending');
  const processingVendors = vendorInfo.filter((vendor) => vendor.status === 'processing' || vendor.status === 'sent');
  const sentVendors = vendorInfo.filter((vendor) => vendor.status === 'sent');

  const allCompleted = successfulVendors.length === vendorIds.length;
  const anyMaxRetriesExceeded = maxRetriesExceededVendors.length > 0;
  const allPending = pendingVendors.length === vendorIds.length;
  const someProcessing = processingVendors.length > 0;

  const now = Date.now();
  const shouldTimeout = vendorInfo.some((vendor) => {
    if (!vendor.lastAttemptAt) return false;
    const timeSinceLastAttempt = now - new Date(vendor.lastAttemptAt).getTime();

    if (vendor.status === 'pending' && timeSinceLastAttempt > MAX_FULFILLMENT_TIMEOUT) {
      logger.warn('Vendor has been pending for too long, considering as timeout', {
        vendorId: vendor.vendor_id,
        status: vendor.status,
        timeSinceLastAttempt: `${Math.floor(timeSinceLastAttempt / 1000)}s`,
        timeoutThreshold: `${Math.floor(MAX_FULFILLMENT_TIMEOUT / 1000)}s`,
      });
      return true;
    }

    return timeSinceLastAttempt > MAX_FULFILLMENT_TIMEOUT;
  });

  return {
    allCompleted,
    sentVendors,
    anyMaxRetriesExceeded,
    allPending,
    someProcessing,
    shouldTimeout,
    successfulVendors,
    failedVendors,
    maxRetriesExceededVendors,
    pendingVendors,
    processingVendors,
    totalVendors: vendorIds.length,
  };
}

export function triggerCoordinatorCheck(checkoutSessionId: string, invoiceId: string, triggeredBy: string) {
  const jobId = `coordinator-${checkoutSessionId}-${Date.now()}`;

  return fulfillmentCoordinatorQueue.push({
    id: jobId,
    job: {
      checkoutSessionId,
      invoiceId,
      triggeredBy,
    },
  });
}

export async function triggerCommissionProcess(checkoutSessionId: string, invoiceId: string): Promise<void> {
  logger.info('Triggering commission process', { checkoutSessionId, invoiceId });

  const checkoutSession = await CheckoutSession.findByPk(checkoutSessionId);
  if (!checkoutSession) {
    logger.error('Checkout session not found[triggerCommissionProcess]', { checkoutSessionId });
    return;
  }

  if (!invoiceId) {
    logger.warn('Invoice ID not found[triggerCommissionProcess]', { checkoutSessionId, invoiceId });
  }

  const invoice = await Invoice.findByPk(invoiceId || checkoutSession.invoice_id);
  if (!invoice) {
    logger.error('Invoice not found[triggerCommissionProcess]', { invoiceId });
    return;
  }
  const paymentIntent = await PaymentIntent.findOne({
    where: {
      [Op.or]: [{ id: invoice.payment_intent_id || checkoutSession.payment_intent_id }, { invoice_id: invoiceId }],
    },
  });

  if (!paymentIntent) {
    logger.error('Payment intent not found[triggerCommissionProcess]', { checkoutSessionId });
    return;
  }

  await VendorFulfillmentService.createVendorPayouts(checkoutSession, paymentIntent);
  await checkoutSession.update({ fulfillment_status: 'completed' });

  if (paymentIntent) {
    const jobId = `deposit-vault-${paymentIntent.currency_id}`;
    const existingJob = await depositVaultQueue.get(jobId);

    if (!existingJob) {
      depositVaultQueue.push({
        id: jobId,
        job: { currencyId: paymentIntent.currency_id },
      });
    }
  } else {
    logger.error('Payment intent not found for invoice', { invoiceId });
  }

  logger.info('Commission process triggered successfully', {
    checkoutSessionId,
  });
}

export async function initiateFullRefund(invoiceId: string, reason: string): Promise<void> {
  logger.warn('Initiating full refund with compensation', {
    invoiceId,
    reason,
  });

  try {
    const paymentIntent = await PaymentIntent.findOne({ where: { invoice_id: invoiceId } });
    const checkoutSession = await CheckoutSession.findByInvoiceId(invoiceId);

    if (!checkoutSession || !paymentIntent) {
      logger.error('Missing data for full refund', {
        invoiceId,
        paymentIntentId: paymentIntent?.id,
        checkoutSessionId: checkoutSession?.id,
        hasCheckoutSession: !!checkoutSession,
        hasPaymentIntent: !!paymentIntent,
      });
      return;
    }

    await checkoutSession.update({ fulfillment_status: 'cancelled' });
    await requestReturnsFromCompletedVendors(checkoutSession, reason);

    // Cancel subscription if this refund is for a subscription
    if (checkoutSession.subscription_id) {
      await cancelSubscriptionForRefund(checkoutSession.subscription_id, reason);
    }

    // Calculate remaining amount using the same logic as subscription createProration
    const refunds = await Refund.findAll({
      where: {
        status: { [Op.not]: 'canceled' },
        payment_intent_id: paymentIntent.id,
        type: 'refund',
      },
    });
    const refundAmount = refunds.reduce((acc, x) => acc.add(new BN(x.amount || '0')), new BN(0));

    // Calculate remaining amount, similar to subscription logic
    const calcRemaining = (amount: BN, subtract: BN) =>
      amount.sub(subtract).lt(new BN(0)) ? '0' : amount.sub(subtract).toString();

    const remaining = calcRemaining(new BN(paymentIntent.amount), refundAmount);

    // If no remaining amount or already fully refunded, skip
    if (new BN(remaining).lte(new BN('0'))) {
      logger.info('Payment already fully refunded, skipping', {
        invoiceId,
        paymentAmount: paymentIntent.amount,
        totalRefundAmount: refundAmount.toString(),
        remaining,
      });
      return;
    }

    const refund = await Refund.create({
      type: 'refund',
      livemode: paymentIntent.livemode,
      amount: remaining,
      description: `${new BN(remaining).eq(new BN(paymentIntent.amount)) ? 'Full' : 'Partial'} refund due to ${reason}`,
      status: 'pending',
      reason,
      currency_id: paymentIntent.currency_id,
      customer_id: paymentIntent.customer_id || '',
      payment_method_id: paymentIntent.payment_method_id,
      payment_intent_id: paymentIntent.id,
      invoice_id: paymentIntent.invoice_id,
      subscription_id: checkoutSession.subscription_id || undefined,
      attempt_count: 0,
      attempted: false,
      next_attempt: 0,
      last_attempt_error: null,
      starting_balance: '0',
      ending_balance: '0',
      starting_token_balance: {},
      ending_token_balance: {},
      metadata: {
        checkout_session_id: checkoutSession.id,
        refund_reason: reason,
        auto_refund: true,
        requested_by: 'coordinator',
        ...(checkoutSession.subscription_id && { subscription_id: checkoutSession.subscription_id }),
      },
    });

    logger.info('Full refund created, triggering refund processing', {
      refundId: refund.id,
      checkoutSessionId: checkoutSession.id,
      invoiceId,
      amount: refund.amount,
      reason,
    });
  } catch (error: any) {
    logger.error('Failed to create full refund', {
      invoiceId,
      reason,
      error: error.message,
    });
  }
}

/**
 * Cancel subscription when full refund is initiated due to vendor fulfillment failure
 */
async function cancelSubscriptionForRefund(subscriptionId: string, reason: string): Promise<void> {
  try {
    const subscription = await Subscription.findByPk(subscriptionId);
    if (!subscription) {
      logger.warn('Subscription not found for cancellation', { subscriptionId });
      return;
    }

    // Check if subscription is already canceled
    if (subscription.status === 'canceled') {
      logger.info('Subscription already canceled, skipping', { subscriptionId });
      return;
    }

    const now = dayjs().unix() + 3;
    const haveStake = !!subscription.payment_details?.arcblock?.staking?.tx_hash;

    // Prepare cancellation details
    const updates: Partial<Subscription> = {
      status: 'canceled',
      cancel_at: now,
      canceled_at: now,
      cancelation_details: {
        comment: `Canceled due to vendor fulfillment failure: ${reason}`,
        reason: 'vendor_fulfillment_failed',
        feedback: 'vendor_issue',
        return_stake: haveStake, // Return stake when canceled due to vendor failure
        slash_stake: false,
        slash_reason: '',
      },
    };

    // Update subscription
    await subscription.update(updates);

    // Schedule cancellation job
    await addSubscriptionJob(subscription, 'cancel', true, updates.cancel_at);

    // Update scheduled tasks
    await new SubscriptionWillCanceledSchedule().reScheduleSubscriptionTasks([subscription]);

    logger.info('Subscription canceled due to vendor fulfillment failure', {
      subscriptionId: subscription.id,
      customerId: subscription.customer_id,
      reason,
      cancelAt: subscription.cancel_at,
      returnStake: haveStake,
    });
  } catch (error: any) {
    logger.error('Failed to cancel subscription for refund', {
      subscriptionId,
      reason,
      error,
    });
  }
}

async function requestReturnsFromCompletedVendors(checkoutSession: CheckoutSession, reason: string): Promise<void> {
  logger.info('Starting return request process', {
    checkoutSessionId: checkoutSession.id,
    reason,
  });

  try {
    const vendorInfos = (checkoutSession.vendor_info as VendorInfo[]) || [];
    const completedVendors = vendorInfos.filter((vendor) => vendor.status === 'completed');

    if (completedVendors.length === 0) {
      logger.info('No completed vendors to request returns from', { checkoutSessionId: checkoutSession.id });
      return;
    }

    logger.info(`Found ${completedVendors.length} completed vendors requiring return requests`, {
      checkoutSessionId: checkoutSession.id,
      completedVendorIds: completedVendors.map((v) => v.vendor_id),
    });

    const returnRequestPromises = completedVendors.map((vendor) => {
      return requestReturnFromSingleVendor(checkoutSession, vendor, reason);
    });

    const returnResults = await Promise.allSettled(returnRequestPromises);

    returnResults.forEach((result, index) => {
      const vendor = completedVendors[index];
      if (vendor) {
        if (result.status === 'fulfilled') {
          logger.info('Return request submitted successfully', {
            vendorId: vendor.vendor_id,
            orderId: vendor.order_id,
          });
        } else {
          logger.error('Return request failed', {
            vendorId: vendor.vendor_id,
            orderId: vendor.order_id,
            error: result.reason,
          });
        }
      }
    });

    logger.info('Return request process completed', {
      checkoutSessionId: checkoutSession.id,
      totalVendors: completedVendors.length,
      successful: returnResults.filter((r) => r.status === 'fulfilled').length,
      failed: returnResults.filter((r) => r.status === 'rejected').length,
    });
  } catch (error: any) {
    logger.error('Return request process failed', {
      checkoutSessionId: checkoutSession.id,
      error: error.message,
    });
  }
}

async function requestReturnFromSingleVendor(
  checkoutSession: CheckoutSession,
  vendor: VendorInfo,
  reason: string
): Promise<void> {
  logger.info('Requesting return for vendor', {
    checkoutSessionId: checkoutSession.id,
    vendorId: vendor.vendor_id,
    orderId: vendor.order_id,
    reason,
  });

  try {
    const vendorAdapter = await VendorFulfillmentService.getVendorAdapter(vendor.vendor_key);
    if (!vendorAdapter) {
      throw new Error(`No adapter found for vendor: ${vendor.vendor_id}`);
    }

    // revenue has not been split yet, so no refund operation is needed.
    const returnResult = await vendorAdapter.requestReturn({
      orderId: vendor.order_id,
      reason: `Return request due to: ${reason}`,
      customParams: {
        returnType: 'order_failure',
        originalAmount: vendor.amount,
      },
    });

    const { code } = returnResult;
    let status: 'pending' | 'rejected' = 'pending';
    if (code) {
      status = 'rejected';
    }

    await updateSingleVendorInfo(checkoutSession.id, vendor.vendor_id, {
      status: 'return_requested',
      returnRequest: {
        reason,
        requestedAt: new Date().toISOString(),
        status,
        returnDetails: returnResult.message,
      },
    });

    logger.info('Return request submitted successfully', {
      vendorId: vendor.vendor_id,
      orderId: vendor.order_id,
      returnResult,
    });
  } catch (error: any) {
    logger.error('Return request failed', {
      vendorId: vendor.vendor_id,
      orderId: vendor.order_id,
      error,
    });

    await updateSingleVendorInfo(checkoutSession.id, vendor.vendor_id, {
      status: 'return_requested',
      error_message: `Return request failed: ${error.message}`,
    });
  }
}
