/**
 * PDF Worker
 *
 * Verarbeitet PDF-Generierungs-Jobs aus der Queue.
 * Nutzt den PDF-Service für die eigentliche Generierung.
 */

import { Worker, Job } from 'bullmq'
import { QUEUE_NAMES, getQueueRedisConnection } from '../queue-service'
import type { PdfJobData, PdfJobResult } from '../jobs/pdf-job'
import {
  generatePdfFromHtml,
  generatePdfFromUrl,
  generatePdfFilename,
  closeBrowser,
} from '../../pdf/pdf-service'

// Worker-Konfiguration
const CONCURRENCY = parseInt(process.env.QUEUE_PDF_CONCURRENCY || '2', 10)

/**
 * PDF Job Processor
 */
async function processPdfJob(job: Job<PdfJobData>): Promise<PdfJobResult> {
  const {
    source,
    html,
    url,
    outputPath,
    filename,
    options = {},
    tenantId,
    documentType,
  } = job.data

  console.log(`[PdfWorker] Processing job ${job.id} for tenant ${tenantId} (source: ${source})`)

  const startTime = Date.now()

  try {
    // Dateiname generieren falls nicht angegeben
    const targetFilename = filename || outputPath || generatePdfFilename('document', tenantId, documentType)

    let result

    if (source === 'html') {
      if (!html) {
        throw new Error('HTML content is required for source="html"')
      }

      result = await generatePdfFromHtml(html, options, outputPath ? targetFilename : undefined)
    } else if (source === 'url') {
      if (!url) {
        throw new Error('URL is required for source="url"')
      }

      result = await generatePdfFromUrl(url, options, outputPath ? targetFilename : undefined)
    } else {
      throw new Error(`Invalid source: ${source}`)
    }

    if (!result.success) {
      throw new Error(result.error || 'PDF generation failed')
    }

    const jobResult: PdfJobResult = {
      success: true,
      outputPath: result.outputPath,
      filename: result.filename || targetFilename,
      pageCount: result.pageCount,
      fileSize: result.fileSize,
      timestamp: new Date().toISOString(),
      duration: Date.now() - startTime,
    }

    // Buffer als Base64 zurückgeben wenn kein outputPath
    if (!outputPath && result.buffer) {
      jobResult.buffer = result.buffer.toString('base64')
    }

    console.log(`[PdfWorker] Job ${job.id} completed: ${result.fileSize} bytes, ${result.pageCount} pages`)

    return jobResult
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
    console.error(`[PdfWorker] Job ${job.id} failed:`, errorMessage)

    // Error werfen damit BullMQ Retry-Logik greift
    throw error
  }
}

/**
 * PDF Worker Instanz
 */
let pdfWorker: Worker<PdfJobData, PdfJobResult> | null = null

/**
 * Startet den PDF Worker
 */
export function startPdfWorker(): Worker<PdfJobData, PdfJobResult> {
  if (pdfWorker) {
    console.warn('[PdfWorker] Worker already running')
    return pdfWorker
  }

  pdfWorker = new Worker<PdfJobData, PdfJobResult>(
    QUEUE_NAMES.PDF,
    processPdfJob,
    {
      connection: getQueueRedisConnection(),
      concurrency: CONCURRENCY,
      // Stalled Job Detection (PDF-Jobs können länger dauern)
      stalledInterval: 60000, // 60s
      maxStalledCount: 1,
      // Längerer Lock für PDF-Generierung
      lockDuration: 120000, // 2 Minuten
    },
  )

  // Event Handlers
  pdfWorker.on('ready', () => {
    console.log(`[PdfWorker] Ready (concurrency: ${CONCURRENCY})`)
  })

  pdfWorker.on('completed', (job, result) => {
    console.log(
      `[PdfWorker] Job ${job.id} completed in ${Date.now() - job.timestamp}ms (${result.fileSize} bytes)`,
    )
  })

  pdfWorker.on('failed', (job, error) => {
    console.error(
      `[PdfWorker] Job ${job?.id} failed after ${job?.attemptsMade} attempts:`,
      error.message,
    )
  })

  pdfWorker.on('stalled', (jobId) => {
    console.warn(`[PdfWorker] Job ${jobId} stalled`)
  })

  pdfWorker.on('error', (error) => {
    console.error('[PdfWorker] Error:', error)
  })

  return pdfWorker
}

/**
 * Stoppt den PDF Worker
 */
export async function stopPdfWorker(): Promise<void> {
  if (pdfWorker) {
    console.log('[PdfWorker] Stopping...')
    await pdfWorker.close()
    pdfWorker = null

    // Browser schließen
    await closeBrowser()

    console.log('[PdfWorker] Stopped')
  }
}

/**
 * Gibt die Worker-Instanz zurück (falls aktiv)
 */
export function getPdfWorker(): Worker<PdfJobData, PdfJobResult> | null {
  return pdfWorker
}
