import { events } from '../../libs/event';
import logger from '../../libs/logger';
import createQueue from '../../libs/queue';
import { Invoice } from '../../store/models';
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 { depositVaultQueue } from '../payment';
import { startVendorFulfillment, triggerCommissionProcess, triggerCoordinatorCheck } from './fulfillment-coordinator';

type VendorCommissionJob = {
  invoiceId: string;
  retryOnError?: boolean;
};

async function checkIfPaymentIntentHasVendors(checkoutSession: CheckoutSession): Promise<boolean> {
  try {
    // Extract price_ids from line_items, then find corresponding product_ids
    const priceIds = checkoutSession.line_items.map((item: any) => item.price_id).filter(Boolean);

    if (priceIds.length === 0) {
      logger.warn('No price IDs found in checkout session line items', {
        checkoutSessionId: checkoutSession.id,
      });
      return false;
    }

    // Find corresponding product_ids through price_ids
    const prices = await Price.findAll({
      where: { id: priceIds },
      attributes: ['id', 'product_id'],
    });

    const productIds = prices.map((price) => price.product_id).filter(Boolean);

    if (productIds.length === 0) {
      logger.warn('No product IDs found from prices', {
        checkoutSessionId: checkoutSession.id,
        priceIds,
      });
      return false;
    }

    // Get product information
    const products = await Product.findAll({
      where: { id: productIds },
      attributes: ['id', 'vendor_config'],
    });

    // Check if any product has vendor configuration
    const hasVendorConfig = products.some((product) => product.vendor_config && product.vendor_config.length > 0);
    return hasVendorConfig;
  } catch (error: any) {
    logger.error('Failed to check vendor configuration', {
      error,
    });
    return false;
  }
}

async function executeDirectDepositVault(invoice: Invoice): Promise<void> {
  const currencyId = invoice.currency_id;
  const exist = await depositVaultQueue.get(`deposit-vault-${currencyId}`);
  if (!exist) {
    depositVaultQueue.push({
      id: `deposit-vault-${currencyId}`,
      job: { currencyId },
    });
    logger.info('Deposit vault job queued', {
      paymentIntentId: invoice.payment_intent_id,
      currencyId,
    });
  } else {
    logger.info('Deposit vault job already exists', {
      paymentIntentId: invoice.payment_intent_id,
      currencyId,
    });
  }
}

export const handleVendorCommission = async (job: VendorCommissionJob) => {
  logger.info('handle vendor commission', job);

  let checkoutSession: CheckoutSession | null = null;
  try {
    const invoice = await Invoice.findByPk(job.invoiceId);
    if (!invoice) {
      logger.warn('invoice not found', { id: job.invoiceId });
      return;
    }

    // Find CheckoutSession through PaymentIntent
    checkoutSession = await CheckoutSession.findByInvoiceId(invoice.id);
    if (!checkoutSession) {
      await executeDirectDepositVault(invoice);
      return;
    }

    const hasVendorConfig = await checkIfPaymentIntentHasVendors(checkoutSession);
    if (!hasVendorConfig) {
      await executeDirectDepositVault(invoice);
      return;
    }

    logger.info('Vendor configuration found, starting fulfillment process', {
      invoiceId: invoice.id,
    });

    if (checkoutSession.fulfillment_status === 'completed') {
      logger.info('CheckoutSession already completed, directly trigger commission process', {
        checkoutSessionId: checkoutSession.id,
      });
      await triggerCommissionProcess(checkoutSession.id, invoice.id);
      return;
    }

    await startVendorFulfillment(checkoutSession.id, invoice.id);
  } catch (error: any) {
    logger.error('Vendor commission decision failed, fallback to direct deposit vault', {
      invoiceId: job.invoiceId,
      error,
    });

    if (!checkoutSession) {
      logger.error('CheckoutSession not found via any method[handleVendorCommission]', {
        invoiceId: job.invoiceId,
      });
      return;
    }

    try {
      triggerCoordinatorCheck(checkoutSession.id, job.invoiceId, 'vendor_commission_decision_failed');
    } catch (err: any) {
      logger.error('Failed to trigger coordinator check[handleVendorCommission]', { error: err });
    }
  }
};

export const vendorCommissionQueue = createQueue<VendorCommissionJob>({
  name: 'vendor-commission',
  onJob: handleVendorCommission,
  options: {
    concurrency: 3,
    maxRetries: 3,
    enableScheduledJob: true,
  },
});

export const startVendorCommissionQueue = async () => {
  const payments = await PaymentIntent.findAll({
    where: {
      status: ['requires_capture', 'processing'],
      capture_method: 'automatic',
    },
  });

  payments.forEach(async (x) => {
    const id = `vendor-commission-${x.invoice_id}`;
    const exist = await vendorCommissionQueue.get(id);
    if (!exist && x.invoice_id) {
      vendorCommissionQueue.push({ id, job: { invoiceId: x.invoice_id, retryOnError: true } });
    }
  });
};

events.on('invoice.paid', async (invoice) => {
  try {
    const id = `vendor-commission-${invoice.id}`;
    const exist = await vendorCommissionQueue.get(id);
    if (exist) {
      logger.info('Vendor commission job already exists, skipping', { id });
      return;
    }

    vendorCommissionQueue.push({
      id,
      job: { invoiceId: invoice.id, retryOnError: true },
    });
  } catch (error) {
    logger.error('Failed to trigger vendor commission queue', { invoiceId: invoice.id, error });
  }
});
