/**
 * PDF Service (pdfmake) - Server
 *
 * Server-side PDF rendering using pdfmake.
 * Converts PDFDocument schema to pdfmake format and uploads to storage.
 *
 * Key differences from React-PDF:
 * - No React reconciler dependency (avoids React 19 async scheduling issues)
 * - Declarative JSON-based document definition
 * - Pure JavaScript, no JSX needed
 *
 * Uses shared conversion logic from ../shared/convert.ts for consistency
 * with the browser service.
 *
 * @see https://pdfmake.github.io/docs/
 */
import { createRequire } from 'module'
import type { Readable } from 'stream'
import type { TDocumentDefinitions } from 'pdfmake/interfaces'

// Server-side pdfmake exports PdfPrinter class directly (CommonJS module)
const require = createRequire(import.meta.url)
const PdfPrinter = require('pdfmake') as new (fonts: Record<string, FontDef>) => PdfPrinterInstance

// Import Roboto fonts from pdfmake's vfs_fonts (base64 encoded)
const vfsFonts = require('pdfmake/build/vfs_fonts') as Record<string, string>

import { defaultTheme } from '../themes'
import type { PDFTheme } from '../themes'
import type { PDFDocument } from '../types'
import { convertDocument } from '../shared/convert'

// ============================================================================
// Server-side pdfmake types (not in @types/pdfmake which is browser-focused)
// ============================================================================

interface FontDef {
  normal: string | Buffer
  bold: string | Buffer
  italics: string | Buffer
  bolditalics: string | Buffer
}

interface PdfPrinterInstance {
  createPdfKitDocument(docDefinition: TDocumentDefinitions): Readable & { end(): void }
}

// ============================================================================
// Font Configuration
// ============================================================================

// Convert base64 font data from vfs_fonts to Buffers for server-side use
// This gives us Roboto fonts consistent with browser rendering
const fonts: Record<string, FontDef> = {
  Roboto: {
    normal: Buffer.from(vfsFonts['Roboto-Regular.ttf'], 'base64'),
    bold: Buffer.from(vfsFonts['Roboto-Medium.ttf'], 'base64'),
    italics: Buffer.from(vfsFonts['Roboto-Italic.ttf'], 'base64'),
    bolditalics: Buffer.from(vfsFonts['Roboto-MediumItalic.ttf'], 'base64')
  },
  // Keep standard PDF fonts as fallbacks
  Helvetica: {
    normal: 'Helvetica',
    bold: 'Helvetica-Bold',
    italics: 'Helvetica-Oblique',
    bolditalics: 'Helvetica-BoldOblique'
  },
  Courier: {
    normal: 'Courier',
    bold: 'Courier-Bold',
    italics: 'Courier-Oblique',
    bolditalics: 'Courier-BoldOblique'
  },
  Times: {
    normal: 'Times-Roman',
    bold: 'Times-Bold',
    italics: 'Times-Italic',
    bolditalics: 'Times-BoldItalic'
  }
}

// Create printer instance with font configuration
const printer = new PdfPrinter(fonts)

// ============================================================================
// Stream to Buffer Helper
// ============================================================================

/**
 * Converts a readable stream to a Buffer
 */
function streamToBuffer(stream: Readable): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const chunks: Buffer[] = []
    stream.on('data', (chunk: Buffer) => chunks.push(chunk))
    stream.on('end', () => resolve(Buffer.concat(chunks)))
    stream.on('error', reject)
  })
}

// ============================================================================
// Storage Service Interface
// ============================================================================

/**
 * Storage service interface for PDF uploads
 * Compatible with apps/api/src/storage/service.ts (StorageService)
 */
export interface IStorageService {
  upload(params: {
    organizationId: string
    bucket: string
    path: string
    file: Buffer | Blob
    contentType: string
    upsert?: boolean
  }): Promise<{ path: string; fullPath: string; size: number }>

  createSignedUrl(params: {
    organizationId: string
    bucket: string
    path: string
    expiresIn: number
  }): Promise<{ signedUrl: string; path: string; expiresAt: Date }>
}

// ============================================================================
// Service Types
// ============================================================================

/**
 * Parameters for PDF rendering
 */
export interface PdfMakeRenderParams {
  organizationId: string
  document: PDFDocument
  theme?: Partial<PDFTheme>
  storage: {
    bucket: string
    path: string
  }
}

/**
 * Result of PDF rendering
 */
export interface PdfMakeRenderResult {
  success: boolean
  pdfUrl: string
  size: number
}

// ============================================================================
// PDF Service Class
// ============================================================================

/**
 * PdfMakeService
 *
 * Service class for rendering PDF documents using pdfmake and uploading to storage.
 * Uses constructor injection for the storage service dependency.
 */
export class PdfMakeService {
  constructor(private storageService: IStorageService) {}

  /**
   * Renders a PDF document and uploads to storage
   *
   * @param params - Render parameters including document, theme, and storage config
   * @returns Result with success status, PDF URL, and file size
   */
  async render(params: PdfMakeRenderParams): Promise<PdfMakeRenderResult> {
    const { document, theme: themeOverride, storage } = params

    // Merge theme with defaults
    const theme: PDFTheme = themeOverride
      ? { ...defaultTheme, ...themeOverride }
      : defaultTheme

    // Convert to pdfmake document definition
    const docDefinition = convertDocument(document, theme)

    // Create PDF and get buffer using server-side API
    const pdfDoc = printer.createPdfKitDocument(docDefinition)
    // Must call end() BEFORE awaiting the stream - this signals the PDF is complete
    pdfDoc.end()
    const buffer = await streamToBuffer(pdfDoc)

    // Upload to storage
    await this.storageService.upload({
      organizationId: params.organizationId,
      bucket: storage.bucket,
      path: storage.path,
      file: buffer,
      contentType: 'application/pdf',
      upsert: true // Allow overwriting existing files
    })

    // Create signed URL for accessing the PDF (24 hour expiry)
    const urlResult = await this.storageService.createSignedUrl({
      organizationId: params.organizationId,
      bucket: storage.bucket,
      path: storage.path,
      expiresIn: 86400 // 24 hours
    })

    return {
      success: true,
      pdfUrl: urlResult.signedUrl,
      size: buffer.byteLength,
    }
  }

  /**
   * Renders a PDF document to a buffer (for testing without storage)
   *
   * @param params - Render parameters including document and theme
   * @returns Buffer containing the PDF
   */
  async renderToBuffer(params: Omit<PdfMakeRenderParams, 'storage'>): Promise<Buffer> {
    const { document, theme: themeOverride } = params

    // Merge theme with defaults
    const theme: PDFTheme = themeOverride
      ? { ...defaultTheme, ...themeOverride }
      : defaultTheme

    // Convert to pdfmake document definition
    const docDefinition = convertDocument(document, theme)

    // Create PDF and get buffer using server-side API
    const pdfDoc = printer.createPdfKitDocument(docDefinition)
    // Must call end() BEFORE awaiting the stream - this signals the PDF is complete
    pdfDoc.end()
    return streamToBuffer(pdfDoc)
  }
}
