import { Price, PaymentCurrency } from '../store/models';
import { getQuoteService, type RateResult } from './quote-service';
import { getExchangeRateService } from './exchange-rate';
import logger from './logger';

export interface InvoiceItemInput {
  price_id: string;
  quantity: number;
  amount: string;
  subscription_item_id?: string;
  description: string;
  period?: { start: number; end: number };
  metadata?: Record<string, any>;
  discountable?: boolean;
  discount_amounts?: any[];
}

export interface InvoiceItemWithQuote extends InvoiceItemInput {
  quote_id?: string;
}

/**
 * Generate quotes for dynamic pricing invoice items
 * This function checks each invoice item's price and generates a quote if it uses dynamic pricing
 */
export async function generateQuotesForInvoiceItems(params: {
  invoiceId: string;
  items: InvoiceItemInput[];
  currencyId: string;
}): Promise<InvoiceItemWithQuote[]> {
  const { invoiceId, items, currencyId } = params;

  if (!items || items.length === 0) {
    return [];
  }

  // Load currency with payment method
  const currency = await PaymentCurrency.findByPk(currencyId, {
    include: [{ association: 'payment_method' }],
  });
  if (!currency) {
    throw new Error(`Currency ${currencyId} not found`);
  }

  // Get exchange rate once for all dynamic prices (for efficiency)
  // For ArcBlock payment method, always use ABT for exchange rate
  const exchangeRateService = getExchangeRateService();
  const rateSymbol = (currency as any).payment_method?.type === 'arcblock' ? 'ABT' : currency.symbol;
  let rateResult: RateResult | null = null;

  const quoteService = getQuoteService();
  const enrichedItems: InvoiceItemWithQuote[] = [];

  // Note: Sequential processing is intentional here
  // 1. Prices may not exist (early continue)
  // 2. Exchange rate is fetched once and reused (rateResult)
  // 3. Quote failures must be handled immediately (P0 critical)
  // eslint-disable-next-line no-restricted-syntax
  for (const item of items) {
    // eslint-disable-next-line no-await-in-loop
    const price = await Price.findByPk(item.price_id);
    if (!price) {
      logger.warn('Price not found for invoice item', { priceId: item.price_id, invoiceId });
      enrichedItems.push(item);
      // eslint-disable-next-line no-continue
      continue;
    }

    // Skip items with zero or negative quantity (free trial, metered billing outside billing period)
    // These items don't require quote generation
    if (item.quantity <= 0) {
      enrichedItems.push(item);
      // eslint-disable-next-line no-continue
      continue;
    }

    // Check if price uses dynamic pricing
    if (price.pricing_type !== 'dynamic') {
      // Fixed pricing - use item amount as-is
      enrichedItems.push(item);
      // eslint-disable-next-line no-continue
      continue;
    }

    // Dynamic pricing - generate quote
    try {
      // Get exchange rate if not already fetched
      if (!rateResult) {
        // eslint-disable-next-line no-await-in-loop
        rateResult = await exchangeRateService.getRate(rateSymbol);
      }

      // Create quote for this invoice item
      // eslint-disable-next-line no-await-in-loop
      const { quote } = await quoteService.createQuoteWithRate({
        price_id: item.price_id,
        invoice_id: invoiceId,
        target_currency_id: currencyId,
        quantity: item.quantity,
        rateResult,
      });

      logger.info('Generated quote for invoice item', {
        invoiceId,
        priceId: item.price_id,
        quoteId: quote.id,
        quotedAmount: quote.quoted_amount,
      });

      // Update item with quote info
      // Only store quote_id in metadata - full quote info is attached dynamically when querying
      // See: invoices.ts attachQuoteMetadataToLines()
      enrichedItems.push({
        ...item,
        amount: quote.quoted_amount,
        quote_id: quote.id,
        metadata: {
          ...item.metadata,
          quote_id: quote.id,
        },
      });
    } catch (error: any) {
      logger.error('Failed to generate quote for invoice item', {
        invoiceId,
        priceId: item.price_id,
        error: error.message,
      });

      // P0 CRITICAL: Do not allow fallback for dynamic pricing
      // Quote is the only source of truth for dynamic pricing amounts
      // If quote generation fails, the invoice creation must fail
      throw new Error(`Failed to generate quote for dynamic price ${item.price_id}: ${error.message}`);
    }
  }

  return enrichedItems;
}

/**
 * Check if any invoice items use dynamic pricing
 */
export async function hasDynamicPricingItems(items: InvoiceItemInput[]): Promise<boolean> {
  if (!items || items.length === 0) {
    return false;
  }

  const priceIds = items.map((item) => item.price_id).filter(Boolean);
  if (priceIds.length === 0) {
    return false;
  }

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

  return prices.some((price) => price.pricing_type === 'dynamic');
}
