/**
 * PDF Job Definition
 *
 * Definiert den PDF-Generierungs-Job für die Queue.
 * Unterstützt HTML-zu-PDF Konvertierung und URL-zu-PDF.
 */

import { Job } from 'bullmq'
import { getQueue, QUEUE_NAMES, defaultJobOptions } from '../queue-service'

// Job-Daten Typen
export interface PdfJobData {
  // Quelle für PDF
  source: 'html' | 'url'
  html?: string // HTML-Content (wenn source='html')
  url?: string // URL zum Rendern (wenn source='url')

  // Output-Konfiguration
  outputPath?: string // Pfad zum Speichern (optional)
  filename?: string // Dateiname für Download

  // PDF-Optionen
  options?: {
    format?: 'A4' | 'A3' | 'Letter' | 'Legal'
    landscape?: boolean
    margin?: {
      top?: string
      right?: string
      bottom?: string
      left?: string
    }
    printBackground?: boolean
    scale?: number
    headerTemplate?: string
    footerTemplate?: string
    displayHeaderFooter?: boolean
  }

  // Tenant-Kontext
  tenantId: number
  tenantSlug?: string

  // Metadaten
  triggeredBy?: string // User ID oder System
  documentType?: 'invoice' | 'report' | 'export' | 'certificate' | 'other'
  correlationId?: string // Für Tracking

  // Optionen
  priority?: 'high' | 'normal' | 'low'
}

export interface PdfJobResult {
  success: boolean
  outputPath?: string // Wo die PDF gespeichert wurde
  buffer?: string // Base64-encoded PDF (wenn kein outputPath)
  filename?: string
  pageCount?: number
  fileSize?: number // In Bytes
  error?: string
  timestamp: string
  duration?: number // Generierungszeit in ms
}

// Priority-Mapping für BullMQ (niedrigere Zahl = höhere Priorität)
const PRIORITY_MAP = {
  high: 1,
  normal: 5,
  low: 10,
}

/**
 * Fügt einen PDF-Job zur Queue hinzu
 */
export async function enqueuePdf(data: PdfJobData): Promise<Job<PdfJobData>> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  // Validierung
  if (data.source === 'html' && !data.html) {
    throw new Error('HTML content required when source is "html"')
  }
  if (data.source === 'url' && !data.url) {
    throw new Error('URL required when source is "url"')
  }

  const jobOptions = {
    ...defaultJobOptions,
    priority: PRIORITY_MAP[data.priority || 'normal'],
    // PDF-Jobs können länger dauern
    attempts: 2,
    backoff: {
      type: 'fixed' as const,
      delay: 5000, // 5s zwischen Retries
    },
    // Job-ID für Deduplizierung (optional)
    jobId: data.correlationId,
  }

  const job = await queue.add('generate-pdf', data, jobOptions)

  console.log(`[PdfQueue] Job ${job.id} queued (source: ${data.source}, type: ${data.documentType || 'other'})`)

  return job
}

/**
 * Fügt einen verzögerten PDF-Job zur Queue hinzu
 */
export async function enqueueDelayedPdf(
  data: PdfJobData,
  delayMs: number,
): Promise<Job<PdfJobData>> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  const job = await queue.add('generate-pdf', data, {
    ...defaultJobOptions,
    priority: PRIORITY_MAP[data.priority || 'normal'],
    delay: delayMs,
    attempts: 2,
  })

  console.log(`[PdfQueue] Delayed job ${job.id} queued (delay: ${delayMs}ms)`)

  return job
}

/**
 * Fügt mehrere PDF-Jobs als Batch zur Queue hinzu
 */
export async function enqueuePdfBatch(
  pdfs: PdfJobData[],
): Promise<Job<PdfJobData>[]> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  const jobs = await queue.addBulk(
    pdfs.map((data) => ({
      name: 'generate-pdf',
      data,
      opts: {
        ...defaultJobOptions,
        priority: PRIORITY_MAP[data.priority || 'normal'],
        attempts: 2,
      },
    })),
  )

  console.log(`[PdfQueue] ${jobs.length} batch jobs queued`)

  return jobs
}

/**
 * Prüft ob ein Job bereits existiert (für Deduplizierung)
 */
export async function isPdfJobPending(correlationId: string): Promise<boolean> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  const job = await queue.getJob(correlationId)
  if (!job) return false

  const state = await job.getState()
  return state === 'waiting' || state === 'active' || state === 'delayed'
}

/**
 * Holt den Status eines PDF-Jobs
 */
export async function getPdfJobStatus(jobId: string): Promise<{
  state: string
  progress: number
  result?: PdfJobResult
  failedReason?: string
} | null> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  const job = await queue.getJob(jobId)
  if (!job) return null

  const [state, progress] = await Promise.all([job.getState(), job.progress])

  return {
    state,
    progress: typeof progress === 'number' ? progress : 0,
    result: job.returnvalue as PdfJobResult | undefined,
    failedReason: job.failedReason,
  }
}

/**
 * Holt das Ergebnis eines abgeschlossenen PDF-Jobs
 */
export async function getPdfJobResult(jobId: string): Promise<PdfJobResult | null> {
  const queue = getQueue(QUEUE_NAMES.PDF)

  const job = await queue.getJob(jobId)
  if (!job) return null

  const state = await job.getState()
  if (state !== 'completed') return null

  return job.returnvalue as PdfJobResult
}
