import { requireAuth } from '@/server/utils/auth';
import { getExpenseById } from '@/server/utils/nocodb';
import { processExpenseWithCurrency } from '@/server/utils/currency';
import { createError } from 'h3';
import { formatDate } from '@/utils/dateUtils';
import PDFDocument from 'pdfkit';
import { getMinioClient } from '@/server/utils/minio';

interface PDFOptions {
  documentName: string;
  subheader?: string;
  groupBy: 'none' | 'payer' | 'category' | 'date';
  includeReceipts: boolean;
  includeReceiptContents: boolean;
  includeSummary: boolean;
  includeDetails: boolean;
  pageFormat: 'A4' | 'Letter' | 'Legal';
  includeProcessingFee?: boolean;
  targetCurrency?: 'USD' | 'EUR';
}

interface Expense {
  Id: number;
  'Establishment Name': string;
  Price: string;
  PriceNumber: number;
  Currency?: string;
  CurrencySymbol?: string;
  DisplayPrice: string;
  DisplayPriceWithEUR?: string;
  PriceEUR?: number;
  PriceUSD?: number;
  ConversionRate?: number;
  Payer: string;
  Category: string;
  'Payment Method': string;
  Time: string;
  Contents?: string;
  Receipt?: any[];
}

export default defineEventHandler(async (event) => {
  await requireAuth(event);
  
  const body = await readBody(event);
  const { expenseIds, options } = body;
  
  if (!expenseIds || !Array.isArray(expenseIds) || expenseIds.length === 0) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Expense IDs are required'
    });
  }
  
  if (!options || !options.documentName) {
    throw createError({
      statusCode: 400,
      statusMessage: 'PDF options with document name are required'
    });
  }
  
  console.log('[expenses/generate-pdf] PDF generation requested for expenses:', expenseIds);
  
  try {
    // Fetch expense data with target currency processing
    const targetCurrency = options.targetCurrency || 'EUR';
    const expenses: Expense[] = [];
    for (const expenseId of expenseIds) {
      const expense = await getExpenseById(expenseId);
      if (expense) {
        const processedExpense = await processExpenseWithCurrency(expense, targetCurrency);
        expenses.push(processedExpense);
      }
    }
    
    if (expenses.length === 0) {
      throw createError({
        statusCode: 404,
        statusMessage: 'No valid expenses found'
      });
    }
    
    // Calculate totals
    const totals = calculateTotals(expenses, options.includeProcessingFee, targetCurrency);
    
    console.log('[expenses/generate-pdf] Successfully calculated totals:', totals);
    console.log('[expenses/generate-pdf] Options received:', options);
    
    // Generate PDF using PDFKit
    const pdfBuffer = await generatePDFWithPDFKit(expenses, options, totals);
    
    // Return PDF as base64 for download
    const pdfBase64 = pdfBuffer.toString('base64');
    
    return {
      success: true,
      data: {
        filename: `${options.documentName.replace(/[^a-zA-Z0-9\-_\s]/g, '_')}.pdf`,
        content: pdfBase64,
        mimeType: 'application/pdf',
        size: pdfBuffer.length
      }
    };
    
  } catch (error: any) {
    console.error('[expenses/generate-pdf] Error generating PDF:', error);
    throw createError({
      statusCode: 500,
      statusMessage: error.message || 'Failed to generate PDF'
    });
  }
});

function calculateTotals(expenses: Expense[], includeProcessingFee: boolean = false, targetCurrency: string = 'EUR') {
  // Calculate target currency total
  const targetTotal = expenses.reduce((sum, exp) => {
    if (targetCurrency.toUpperCase() === 'USD') {
      return sum + (exp.PriceUSD || exp.PriceNumber || 0);
    } else {
      return sum + (exp.PriceEUR || exp.PriceNumber || 0);
    }
  }, 0);
  
  // Calculate EUR total for compatibility
  const eurTotal = expenses.reduce((sum, exp) => sum + (exp.PriceEUR || exp.PriceNumber || 0), 0);
  
  // Calculate USD total for compatibility
  const usdTotal = expenses.reduce((sum, exp) => sum + (exp.PriceUSD || exp.PriceNumber || 0), 0);
  
  // Processing fee is calculated on target currency total
  const processingFee = includeProcessingFee ? targetTotal * 0.05 : 0;
  const finalTotal = targetTotal + processingFee;
  
  return {
    targetTotal,
    eurTotal,
    usdTotal,
    processingFee,
    finalTotal,
    targetCurrency: targetCurrency.toUpperCase(),
    count: expenses.length
  };
}

function getGroupingLabel(groupBy: string): string {
  switch (groupBy) {
    case 'payer': return 'By Person';
    case 'category': return 'By Category';
    case 'date': return 'By Date';
    default: return 'No Grouping';
  }
}

function getPageDimensions(pageFormat: string) {
  switch (pageFormat) {
    case 'Letter':
      return { width: 612, height: 792 }; // 8.5" x 11"
    case 'Legal':
      return { width: 612, height: 1008 }; // 8.5" x 14"
    case 'A4':
    default:
      return { width: 595, height: 842 }; // A4
  }
}

async function generatePDFWithPDFKit(expenses: Expense[], options: PDFOptions, totals: any): Promise<Buffer> {
  return new Promise(async (resolve, reject) => {
    try {
      console.log('[expenses/generate-pdf] Generating PDF with PDFKit...');
      
      const pageDimensions = getPageDimensions(options.pageFormat);
      const doc = new PDFDocument({
        size: [pageDimensions.width, pageDimensions.height],
        margins: { top: 60, bottom: 60, left: 60, right: 60 }
      });
      
      const chunks: Buffer[] = [];
      
      doc.on('data', (chunk) => chunks.push(chunk));
      doc.on('end', () => {
        const pdfBuffer = Buffer.concat(chunks);
        console.log('[expenses/generate-pdf] PDF generated successfully, size:', pdfBuffer.length, 'bytes');
        resolve(pdfBuffer);
      });
      doc.on('error', reject);
      
      // Add header
      addHeader(doc, options);
      
      // Add summary if requested
      if (options.includeSummary) {
        addSummary(doc, totals, options);
      }
      
      // Add expense details if requested
      if (options.includeDetails) {
        await addExpenseTable(doc, expenses, options);
      }
      
      // Add receipt images if requested
      if (options.includeReceipts) {
        await addReceiptImages(doc, expenses);
      }
      
      // Add footer
      addFooter(doc);
      
      doc.end();
      
    } catch (error: any) {
      console.error('[expenses/generate-pdf] PDFKit error:', error);
      reject(new Error(`PDF generation failed: ${error?.message || 'Unknown error'}`));
    }
  });
}

function addHeader(doc: PDFKit.PDFDocument, options: PDFOptions) {
  doc.fontSize(24)
     .font('Helvetica-Bold')
     .text(options.documentName, { align: 'center' });
  
  if (options.subheader) {
    doc.fontSize(16)
       .font('Helvetica')
       .fillColor('#666666')
       .text(options.subheader, { align: 'center' });
  }
  
  // Add line separator
  const y = doc.y + 10;
  doc.moveTo(60, y)
     .lineTo(doc.page.width - 60, y)
     .strokeColor('#333333')
     .lineWidth(2)
     .stroke();
  
  doc.y = y + 20;
  doc.fillColor('#000000'); // Reset color
}

function addSummary(doc: PDFKit.PDFDocument, totals: any, options: PDFOptions) {
  doc.fontSize(18)
     .font('Helvetica-Bold')
     .text('Summary', { continued: false });
  
  doc.y += 10;
  
  // Summary box
  const boxY = doc.y;
  const boxHeight = options.includeProcessingFee ? 140 : 120;
  
  doc.rect(60, boxY, doc.page.width - 120, boxHeight)
     .fillColor('#f5f5f5')
     .fill()
     .strokeColor('#dddddd')
     .stroke();
  
  doc.fillColor('#000000');
  
  // Summary content
  doc.y = boxY + 15;
  doc.fontSize(12)
     .font('Helvetica');
  
  const leftX = 80;
  const targetCurrency = totals.targetCurrency || 'EUR';
  const targetSymbol = targetCurrency === 'USD' ? '$' : '€';
  
  doc.text(`Total Expenses:`, leftX, doc.y, { continued: true })
     .font('Helvetica-Bold')
     .text(` ${totals.count}`, { align: 'left' });
  
  doc.font('Helvetica')
     .text(`Subtotal (${targetCurrency}):`, leftX, doc.y + 5, { continued: true })
     .font('Helvetica-Bold')
     .text(` ${targetSymbol}${totals.targetTotal.toFixed(2)}`, { align: 'left' });
  
  // Show the other currency as reference
  if (targetCurrency === 'USD') {
    doc.font('Helvetica')
       .text(`EUR Equivalent:`, leftX, doc.y + 5, { continued: true })
       .font('Helvetica-Bold')
       .text(` €${totals.eurTotal.toFixed(2)}`, { align: 'left' });
  } else {
    doc.font('Helvetica')
       .text(`USD Equivalent:`, leftX, doc.y + 5, { continued: true })
       .font('Helvetica-Bold')
       .text(` $${totals.usdTotal.toFixed(2)}`, { align: 'left' });
  }
  
  if (options.includeProcessingFee) {
    doc.font('Helvetica')
       .text(`Processing Fee (5%):`, leftX, doc.y + 5, { continued: true })
       .font('Helvetica-Bold')
       .text(` ${targetSymbol}${totals.processingFee.toFixed(2)}`, { align: 'left' });
  }
  
  doc.font('Helvetica')
     .text(`Final Total:`, leftX, doc.y + 5, { continued: true })
     .font('Helvetica-Bold')
     .fontSize(14)
     .text(` ${targetSymbol}${totals.finalTotal.toFixed(2)}`, { align: 'left' });
  
  doc.fontSize(12)
     .font('Helvetica')
     .text(`Grouping:`, leftX, doc.y + 5, { continued: true })
     .font('Helvetica-Bold')
     .text(` ${getGroupingLabel(options.groupBy)}`, { align: 'left' });
  
  doc.y = boxY + boxHeight + 20;
}

async function addExpenseTable(doc: PDFKit.PDFDocument, expenses: Expense[], options: PDFOptions) {
  doc.fontSize(18)
     .font('Helvetica-Bold')
     .text('Expense Details', { continued: false });
  
  doc.y += 15;
  
  const tableTop = doc.y;
  const rowHeight = 25;
  const fontSize = 9;
  
  // Column definitions - adjusted for better layout
  const columns = [
    { header: 'Date', width: 65, x: 60 },
    { header: 'Establishment', width: 110, x: 125 },
    { header: 'Category', width: 55, x: 235 },
    { header: 'Payer', width: 50, x: 290 },
    { header: 'Amount', width: 55, x: 340 },
    { header: 'Payment', width: 45, x: 395 }
  ];
  
  if (options.includeReceiptContents) {
    columns.push({ header: 'Description', width: 105, x: 440 });
  }
  
  // Draw table header
  doc.fontSize(fontSize + 1)
     .font('Helvetica-Bold')
     .fillColor('#000000');
  
  // Header background
  doc.rect(60, tableTop, doc.page.width - 120, rowHeight)
     .fillColor('#f2f2f2')
     .fill()
     .strokeColor('#dddddd')
     .stroke();
  
  doc.fillColor('#000000');
  
  columns.forEach(col => {
    doc.text(col.header, col.x, tableTop + 8, { width: col.width, align: 'left' });
  });
  
  let currentY = tableTop + rowHeight;
  
  // Group expenses if needed
  if (options.groupBy === 'none') {
    currentY = await drawExpenseRows(doc, expenses, columns, currentY, rowHeight, fontSize, options);
  } else {
    const groups = groupExpenses(expenses, options.groupBy);
    
    for (const [groupKey, groupExpenses] of Object.entries(groups)) {
      // Check if we need a new page
      if (currentY > doc.page.height - 100) {
        doc.addPage();
        currentY = 60;
      }
      
      // Group header - show EUR total
      const groupEurTotal = groupExpenses.reduce((sum, exp) => sum + (exp.PriceEUR || exp.PriceNumber || 0), 0);
      doc.fontSize(fontSize + 1)
         .font('Helvetica-Bold')
         .fillColor('#000000');
      
      doc.rect(60, currentY, doc.page.width - 120, rowHeight)
         .fillColor('#e7f3ff')
         .fill()
         .strokeColor('#dddddd')
         .stroke();
      
      doc.fillColor('#000000')
         .text(`${groupKey} (${groupExpenses.length} expenses - €${groupEurTotal.toFixed(2)})`, 
               65, currentY + 8, { width: doc.page.width - 130 });
      
      currentY += rowHeight;
      
      // Group expenses
      currentY = await drawExpenseRows(doc, groupExpenses, columns, currentY, rowHeight, fontSize, options);
    }
  }
}

async function drawExpenseRows(
  doc: PDFKit.PDFDocument, 
  expenses: Expense[], 
  columns: any[], 
  startY: number, 
  rowHeight: number, 
  fontSize: number,
  options: PDFOptions
): Promise<number> {
  let currentY = startY;
  
  doc.fontSize(fontSize)
     .font('Helvetica');
  
  expenses.forEach((expense, index) => {
    // Check if we need a new page
    if (currentY > doc.page.height - 100) {
      doc.addPage();
      currentY = 60;
    }
    
    // Alternate row colors
    if (index % 2 === 0) {
      doc.rect(60, currentY, doc.page.width - 120, rowHeight)
         .fillColor('#f9f9f9')
         .fill();
    }
    
    doc.fillColor('#000000');
    
    // Draw row data - show original amount with EUR conversion
    const date = expense.Time ? formatDate(expense.Time) : 'N/A';
    const establishment = expense['Establishment Name'] || 'N/A';
    const category = expense.Category || 'N/A';
    const payer = expense.Payer || 'N/A';
    
    // Display amount with EUR conversion if needed
    let amount;
    if (expense.Currency && expense.Currency.toUpperCase() !== 'EUR' && expense.PriceEUR) {
      const symbol = expense.CurrencySymbol || expense.Currency;
      amount = `${symbol}${expense.PriceNumber?.toFixed(2)} (€${expense.PriceEUR.toFixed(2)})`;
    } else {
      amount = `€${expense.PriceNumber ? expense.PriceNumber.toFixed(2) : '0.00'}`;
    }
    
    const payment = expense['Payment Method'] || 'N/A';
    
    const rowData = [date, establishment, category, payer, amount, payment];
    
    if (options.includeReceiptContents) {
      const description = expense.Contents || 'N/A';
      rowData.push(description.length > 40 ? description.substring(0, 37) + '...' : description);
    }
    
    rowData.forEach((data, colIndex) => {
      if (colIndex < columns.length) {
        doc.text(data, columns[colIndex].x, currentY + 8, { 
          width: columns[colIndex].width - 5, 
          align: 'left',
          ellipsis: true
        });
      }
    });
    
    currentY += rowHeight;
  });
  
  return currentY;
}

function groupExpenses(expenses: Expense[], groupBy: string): Record<string, Expense[]> {
  const groups: Record<string, Expense[]> = {};
  
  expenses.forEach(expense => {
    let groupKey = 'Unknown';
    
    switch (groupBy) {
      case 'payer':
        groupKey = expense.Payer || 'Unknown Payer';
        break;
      case 'category':
        groupKey = expense.Category || 'Unknown Category';
        break;
      case 'date':
        groupKey = expense.Time ? formatDate(expense.Time) : 'Unknown Date';
        break;
    }
    
    if (!groups[groupKey]) {
      groups[groupKey] = [];
    }
    groups[groupKey].push(expense);
  });
  
  return groups;
}

async function addReceiptImages(doc: PDFKit.PDFDocument, expenses: Expense[]) {
  console.log('[expenses/generate-pdf] Adding receipt images...');
  console.log('[expenses/generate-pdf] Total expenses to check:', expenses.length);
  
  // Log receipt data structure for debugging
  expenses.forEach((expense, index) => {
    console.log(`[expenses/generate-pdf] Expense ${index + 1} (ID: ${expense.Id}):`, {
      establishment: expense['Establishment Name'],
      hasReceipt: !!expense.Receipt,
      receiptType: typeof expense.Receipt,
      receiptLength: Array.isArray(expense.Receipt) ? expense.Receipt.length : 'N/A',
      receiptData: expense.Receipt
    });
  });
  
  const expensesWithReceipts = expenses.filter(expense => 
    expense.Receipt && Array.isArray(expense.Receipt) && expense.Receipt.length > 0
  );
  
  console.log('[expenses/generate-pdf] Expenses with receipts:', expensesWithReceipts.length);
  
  if (expensesWithReceipts.length === 0) {
    console.log('[expenses/generate-pdf] No receipts found to include');
    return;
  }
  
  let totalReceiptImages = 0;
  let processedImages = 0;
  let currentReceiptNumber = 0; // Track overall receipt number across all expenses
  
  // Count total receipt images for progress tracking
  expensesWithReceipts.forEach(expense => {
    if (expense.Receipt && Array.isArray(expense.Receipt)) {
      totalReceiptImages += expense.Receipt.length;
    }
  });
  
  console.log('[expenses/generate-pdf] Total receipt images to process:', totalReceiptImages);
  
  for (const expense of expensesWithReceipts) {
    try {
      console.log('[expenses/generate-pdf] Processing receipts for expense:', expense.Id, expense['Establishment Name']);
      
      // Process receipt images - each gets its own page
      if (expense.Receipt && Array.isArray(expense.Receipt)) {
        for (const [receiptIndex, receipt] of expense.Receipt.entries()) {
          currentReceiptNumber++; // Increment overall receipt counter
          
          if (receipt.url || receipt.signedUrl || receipt.directus_files_id?.filename_download || receipt.filename_download) {
            try {
              console.log(`[expenses/generate-pdf] Fetching receipt ${currentReceiptNumber}/${totalReceiptImages} (expense ${expense.Id}, receipt ${receiptIndex + 1}/${expense.Receipt.length})`);
              const imageBuffer = await fetchReceiptImage(receipt);
              
              if (imageBuffer) {
                // Add new page for each receipt image
                doc.addPage();
                
                // Add header section for this receipt
                const headerHeight = 100;
                
                // Header background
                doc.rect(60, 60, doc.page.width - 120, headerHeight)
                   .fillColor('#f8f9fa')
                   .fill()
                   .strokeColor('#dee2e6')
                   .lineWidth(1)
                   .stroke();
                
                doc.fillColor('#000000');
                
                // Receipt header content with overall numbering
                doc.fontSize(16)
                   .font('Helvetica-Bold')
                   .text(`Receipt Image ${currentReceiptNumber} of ${totalReceiptImages}`, 
                         70, 80, { align: 'left' });
                
                // Show amount with EUR conversion
                let amountText;
                if (expense.Currency && expense.Currency.toUpperCase() !== 'EUR' && expense.PriceEUR) {
                  const symbol = expense.CurrencySymbol || expense.Currency;
                  amountText = `${expense['Establishment Name']} - ${symbol}${expense.PriceNumber?.toFixed(2)} (€${expense.PriceEUR.toFixed(2)})`;
                } else {
                  amountText = `${expense['Establishment Name']} - €${expense.PriceNumber?.toFixed(2)}`;
                }
                
                doc.fontSize(14)
                   .font('Helvetica-Bold')
                   .text(amountText, 70, 105, { align: 'left' });
                
                doc.fontSize(12)
                   .font('Helvetica')
                   .text(`Date: ${expense.Time ? formatDate(expense.Time) : 'N/A'}`, 
                         70, 125, { align: 'left' });
                
                doc.fontSize(10)
                   .fillColor('#666666')
                   .text(`Payer: ${expense.Payer || 'N/A'} | Category: ${expense.Category || 'N/A'}`, 
                         70, 140, { align: 'left' });
                
                doc.fillColor('#000000');
                
                // Calculate available space for image (full page minus header and margins)
                const pageWidth = doc.page.width;
                const pageHeight = doc.page.height;
                const margin = 60;
                const imageStartY = 60 + headerHeight + 20; // Header + spacing
                
                const maxImageWidth = pageWidth - (margin * 2);
                const maxImageHeight = pageHeight - imageStartY - margin;
                
                console.log(`[expenses/generate-pdf] Adding large image - Max size: ${maxImageWidth}x${maxImageHeight}, Buffer size: ${imageBuffer.length} bytes`);
                
                // Add the receipt image with maximum size
                try {
                  doc.image(imageBuffer, margin, imageStartY, {
                    fit: [maxImageWidth, maxImageHeight],
                    align: 'center',
                    valign: 'center'
                  });
                  
                  processedImages++;
                  console.log(`[expenses/generate-pdf] Successfully added receipt image ${processedImages}/${totalReceiptImages}`);
                  
                } catch (imageEmbedError: any) {
                  console.error('[expenses/generate-pdf] Error embedding image in PDF:', imageEmbedError);
                  
                  // Add error message on the page
                  doc.fontSize(14)
                     .fillColor('#dc3545')
                     .text('Receipt image could not be embedded', margin, imageStartY + 50, { 
                       align: 'center',
                       width: maxImageWidth
                     });
                  
                  doc.fontSize(12)
                     .fillColor('#6c757d')
                     .text(`Error: ${imageEmbedError.message || 'Unknown error'}`, margin, imageStartY + 80, { 
                       align: 'center',
                       width: maxImageWidth
                     });
                  
                  doc.fillColor('#000000');
                }
                
              } else {
                console.warn(`[expenses/generate-pdf] No image buffer received for receipt ${currentReceiptNumber} of expense ${expense.Id}`);
                
                // Add page with error message
                doc.addPage();
                
                doc.fontSize(16)
                   .font('Helvetica-Bold')
                   .text(`Receipt Image ${currentReceiptNumber} of ${totalReceiptImages}`, 
                         { align: 'center' });
                
                // Show amount with EUR conversion
                let centerAmountText;
                if (expense.Currency && expense.Currency.toUpperCase() !== 'EUR' && expense.PriceEUR) {
                  const symbol = expense.CurrencySymbol || expense.Currency;
                  centerAmountText = `${expense['Establishment Name']} - ${symbol}${expense.PriceNumber?.toFixed(2)} (€${expense.PriceEUR.toFixed(2)})`;
                } else {
                  centerAmountText = `${expense['Establishment Name']} - €${expense.PriceNumber?.toFixed(2)}`;
                }
                
                doc.fontSize(14)
                   .font('Helvetica')
                   .text(centerAmountText, { align: 'center' });
                
                doc.y += 50;
                
                doc.fontSize(12)
                   .fillColor('#dc3545')
                   .text('Receipt image could not be loaded from storage', { align: 'center' });
                
                doc.fillColor('#000000');
              }
              
            } catch (imageError: any) {
              console.error(`[expenses/generate-pdf] Error processing receipt ${currentReceiptNumber} for expense ${expense.Id}:`, imageError);
              
              // Add page with error information
              doc.addPage();
              
              doc.fontSize(16)
                 .font('Helvetica-Bold')
                 .text(`Receipt Image ${currentReceiptNumber} of ${totalReceiptImages}`, 
                       { align: 'center' });
              
              // Show amount with EUR conversion
              let errorAmountText;
              if (expense.Currency && expense.Currency.toUpperCase() !== 'EUR' && expense.PriceEUR) {
                const symbol = expense.CurrencySymbol || expense.Currency;
                errorAmountText = `${expense['Establishment Name']} - ${symbol}${expense.PriceNumber?.toFixed(2)} (€${expense.PriceEUR.toFixed(2)})`;
              } else {
                errorAmountText = `${expense['Establishment Name']} - €${expense.PriceNumber?.toFixed(2)}`;
              }
              
              doc.fontSize(14)
                 .font('Helvetica')
                 .text(errorAmountText, { align: 'center' });
              
              doc.y += 50;
              
              doc.fontSize(12)
                 .fillColor('#dc3545')
                 .text('Error loading receipt image', { align: 'center' });
              
              doc.fontSize(10)
                 .fillColor('#6c757d')
                 .text(`${imageError.message || 'Unknown error'}`, { align: 'center' });
              
              doc.fillColor('#000000');
            }
          } else {
            console.log(`[expenses/generate-pdf] Skipping receipt ${currentReceiptNumber} for expense ${expense.Id} - no valid file path`);
          }
        }
      }
      
    } catch (error) {
      console.error('[expenses/generate-pdf] Error processing receipts for expense:', expense.Id, error);
    }
  }
  
  console.log(`[expenses/generate-pdf] Completed processing ${processedImages}/${totalReceiptImages} receipt images`);
}

async function fetchReceiptImage(receipt: any): Promise<Buffer | null> {
  try {
    // Determine the file path - try multiple possible sources
    let rawPath = null;
    
    // Try different receipt data structures - prioritize signedUrl for S3 URLs
    if (receipt.signedUrl) {
      rawPath = receipt.signedUrl;
    } else if (receipt.url) {
      rawPath = receipt.url;
    } else if (receipt.directus_files_id?.filename_download) {
      rawPath = receipt.directus_files_id.filename_download;
    } else if (receipt.filename_download) {
      rawPath = receipt.filename_download;
    } else if (receipt.id && receipt.filename_disk) {
      rawPath = receipt.filename_disk;
    } else if (typeof receipt === 'string') {
      rawPath = receipt;
    }
    
    if (!rawPath) {
      console.log('[expenses/generate-pdf] No file path found for receipt:', JSON.stringify(receipt, null, 2));
      return null;
    }
    
    console.log('[expenses/generate-pdf] Raw path from receipt:', rawPath);
    
    // Check if this is an S3 URL (HTTP/HTTPS)
    if (rawPath.startsWith('http://') || rawPath.startsWith('https://')) {
      console.log('[expenses/generate-pdf] Detected S3 URL, fetching directly...');
      
      try {
        // Use the signed URL directly without modification to preserve AWS signature
        console.log('[expenses/generate-pdf] Fetching from S3 URL (preserving signature):', rawPath);
        
        // Fetch image directly from S3 URL with minimal headers to avoid signature issues
        const response = await fetch(rawPath, {
          method: 'GET',
          headers: {
            'Accept': 'image/*'
          },
          // Add timeout to prevent hanging
          signal: AbortSignal.timeout(30000) // 30 second timeout
        });
        
        if (!response.ok) {
          console.error(`[expenses/generate-pdf] Failed to fetch image from S3: ${response.status} ${response.statusText}`);
          console.error('[expenses/generate-pdf] Response headers:', Object.fromEntries(response.headers.entries()));
          return null;
        }
        
        // Convert response to buffer
        const arrayBuffer = await response.arrayBuffer();
        const imageBuffer = Buffer.from(arrayBuffer);
        
        console.log('[expenses/generate-pdf] Successfully fetched image from S3 URL, Size:', imageBuffer.length);
        return imageBuffer;
        
      } catch (fetchError: any) {
        console.error('[expenses/generate-pdf] Error fetching from S3 URL:', fetchError.message);
        console.error('[expenses/generate-pdf] Error details:', {
          name: fetchError.name,
          code: fetchError.code,
          message: fetchError.message
        });
        
        // Don't try multiple attempts for signed URLs as they may expire
        return null;
      }
    }
    
    // If not an S3 URL, try MinIO as fallback
    console.log('[expenses/generate-pdf] Not an S3 URL, trying MinIO fallback...');
    
    const client = getMinioClient();
    const bucketName = useRuntimeConfig().minio.bucketName;
    
    // Extract MinIO path from the raw path
    let minioPath = extractMinioPath(rawPath);
    
    if (!minioPath) {
      console.log('[expenses/generate-pdf] Could not extract MinIO path from:', rawPath);
      return null;
    }
    
    console.log('[expenses/generate-pdf] Extracted MinIO path:', minioPath);
    
    // Try multiple possible locations in MinIO
    const possiblePaths = [
      minioPath,
      `receipts/${minioPath}`,
      `expenses/${minioPath}`,
      // Try without any folder prefix
      minioPath.split('/').pop() || minioPath,
      // Try in receipts folder with just filename
      `receipts/${minioPath.split('/').pop() || minioPath}`,
      // Try in expenses folder with just filename
      `expenses/${minioPath.split('/').pop() || minioPath}`
    ];
    
    // Remove duplicates
    const uniquePaths = [...new Set(possiblePaths)];
    
    for (const testPath of uniquePaths) {
      try {
        console.log('[expenses/generate-pdf] Trying MinIO path:', testPath);
        
        // Check if object exists first
        await client.statObject(bucketName, testPath);
        
        // Get the object from MinIO
        const dataStream = await client.getObject(bucketName, testPath);
        
        // Convert stream to buffer
        const chunks: Buffer[] = [];
        
        const imageBuffer = await new Promise<Buffer>((resolve, reject) => {
          dataStream.on('data', (chunk) => chunks.push(chunk));
          dataStream.on('end', () => resolve(Buffer.concat(chunks)));
          dataStream.on('error', reject);
        });
        
        console.log('[expenses/generate-pdf] Successfully fetched image from MinIO path:', testPath, 'Size:', imageBuffer.length);
        return imageBuffer;
        
      } catch (pathError) {
        console.log('[expenses/generate-pdf] MinIO path not found:', testPath);
        continue;
      }
    }
    
    console.log('[expenses/generate-pdf] Could not find image in any of the attempted MinIO paths:', uniquePaths);
    return null;
    
  } catch (error) {
    console.error('[expenses/generate-pdf] Error fetching receipt image:', error);
    return null;
  }
}

/**
 * Extract the MinIO path from an S3 URL or return the path as-is
 */
function extractMinioPath(urlOrPath: string): string | null {
  try {
    // If it's already just a path, return it
    if (!urlOrPath.startsWith('http')) {
      return urlOrPath;
    }
    
    // Parse the URL
    const url = new URL(urlOrPath);
    
    // Extract the pathname (removes query parameters)
    let pathname = decodeURIComponent(url.pathname);
    
    console.log('[expenses/generate-pdf] URL pathname:', pathname);
    
    // For S3 URLs, we need to extract the part after the bucket name
    // Pattern: /database/nc/uploads/path/to/file.jpg
    // We want: uploads/path/to/file.jpg
    
    // Remove leading slash
    if (pathname.startsWith('/')) {
      pathname = pathname.substring(1);
    }
    
    // Look for common patterns
    if (pathname.includes('/uploads/')) {
      // Extract everything from 'uploads/' onwards
      const uploadsIndex = pathname.indexOf('uploads/');
      const extractedPath = pathname.substring(uploadsIndex);
      console.log('[expenses/generate-pdf] Extracted path from uploads pattern:', extractedPath);
      return extractedPath;
    }
    
    if (pathname.includes('/nc/uploads/')) {
      // Extract everything from 'uploads/' onwards
      const uploadsIndex = pathname.indexOf('uploads/');
      const extractedPath = pathname.substring(uploadsIndex);
      console.log('[expenses/generate-pdf] Extracted path from nc/uploads pattern:', extractedPath);
      return extractedPath;
    }
    
    if (pathname.includes('/database/')) {
      // Remove the database prefix
      const databaseIndex = pathname.indexOf('database/');
      const withoutDatabase = pathname.substring(databaseIndex + 'database/'.length);
      console.log('[expenses/generate-pdf] Extracted path after removing database prefix:', withoutDatabase);
      return withoutDatabase;
    }
    
    // If no specific pattern found, return the pathname as-is
    console.log('[expenses/generate-pdf] Using pathname as-is:', pathname);
    return pathname;
    
  } catch (error) {
    console.error('[expenses/generate-pdf] Error parsing URL:', error);
    // If URL parsing fails, try to extract manually
    
    // Remove query parameters manually
    const withoutQuery = urlOrPath.split('?')[0];
    
    // Look for uploads pattern
    if (withoutQuery.includes('/uploads/')) {
      const uploadsIndex = withoutQuery.indexOf('/uploads/');
      return withoutQuery.substring(uploadsIndex + 1); // +1 to remove the leading slash
    }
    
    return null;
  }
}

function addFooter(doc: PDFKit.PDFDocument) {
  doc.fontSize(10)
     .fillColor('#666666')
     .text(`Generated on: ${new Date().toLocaleString()}`, 
           60, doc.page.height - 40, { align: 'right' });
}
