/**
 * PDF Generation API
 *
 * Endpunkt für PDF-Generierung über die Queue oder direkt.
 * Unterstützt HTML-zu-PDF und URL-zu-PDF.
 */

import { getPayload } from 'payload'
import config from '@payload-config'
import { NextRequest, NextResponse } from 'next/server'
import { enqueuePdf, getPdfJobStatus, isQueueAvailable } from '@/lib/queue'
import { generatePdfFromHtml, generatePdfFromUrl } from '@/lib/pdf/pdf-service'
import { logAccessDenied } from '@/lib/audit/audit-service'
import {
  publicApiLimiter,
  rateLimitHeaders,
  validateIpAccess,
  createSafeLogger,
  validateCsrf,
} from '@/lib/security'

const RATE_LIMIT_MAX = 10
const logger = createSafeLogger('API:GeneratePdf')

interface UserWithTenants {
  id: number
  isSuperAdmin?: boolean
  tenants?: Array<{
    tenant: { id: number } | number
  }>
}

/**
 * Prüft ob User Zugriff auf den angegebenen Tenant hat
 */
function userHasAccessToTenant(user: UserWithTenants, tenantId: number): boolean {
  if (user.isSuperAdmin) {
    return true
  }

  if (!user.tenants || user.tenants.length === 0) {
    return false
  }

  return user.tenants.some((t) => {
    const userTenantId = typeof t.tenant === 'object' ? t.tenant.id : t.tenant
    return userTenantId === tenantId
  })
}

/**
 * POST /api/generate-pdf
 *
 * Generiert ein PDF aus HTML oder URL.
 *
 * Body:
 * - tenantId: number (erforderlich)
 * - source: 'html' | 'url' (erforderlich)
 * - html?: string (wenn source='html')
 * - url?: string (wenn source='url')
 * - options?: { format, landscape, margin, printBackground, scale }
 * - queued?: boolean (true = async via Queue, false = sync)
 * - documentType?: string (invoice, report, export, etc.)
 * - filename?: string
 */
export async function POST(req: NextRequest) {
  try {
    // IP-Allowlist prüfen
    const ipCheck = validateIpAccess(req, 'generatePdf')
    if (!ipCheck.allowed) {
      logger.warn(`IP blocked: ${ipCheck.ip}`, { reason: ipCheck.reason })
      return NextResponse.json({ error: 'Access denied' }, { status: 403 })
    }

    // CSRF-Schutz
    const csrfResult = validateCsrf(req)
    if (!csrfResult.valid) {
      logger.warn('CSRF validation failed', { reason: csrfResult.reason })
      return NextResponse.json({ error: 'CSRF validation failed' }, { status: 403 })
    }

    const payload = await getPayload({ config })

    // Authentifizierung prüfen
    const { user } = await payload.auth({ headers: req.headers })

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized - Login required' }, { status: 401 })
    }

    const typedUser = user as UserWithTenants

    // Rate Limiting
    const rateLimit = await publicApiLimiter.check(String(typedUser.id))
    if (!rateLimit.allowed) {
      return NextResponse.json(
        {
          error: 'Rate limit exceeded',
          message: `Maximum ${RATE_LIMIT_MAX} requests per minute.`,
        },
        {
          status: 429,
          headers: rateLimitHeaders(rateLimit, RATE_LIMIT_MAX),
        },
      )
    }

    const body = await req.json()
    const {
      tenantId,
      source,
      html,
      url,
      options = {},
      queued = true,
      documentType,
      filename,
      priority,
    } = body

    // Validierung
    if (!tenantId) {
      return NextResponse.json({ error: 'Missing required field: tenantId' }, { status: 400 })
    }

    const numericTenantId = Number(tenantId)
    if (isNaN(numericTenantId)) {
      return NextResponse.json({ error: 'Invalid tenantId: must be a number' }, { status: 400 })
    }

    if (!source || !['html', 'url'].includes(source)) {
      return NextResponse.json(
        { error: 'Invalid source: must be "html" or "url"' },
        { status: 400 },
      )
    }

    if (source === 'html' && !html) {
      return NextResponse.json(
        { error: 'Missing required field: html (for source="html")' },
        { status: 400 },
      )
    }

    if (source === 'url' && !url) {
      return NextResponse.json(
        { error: 'Missing required field: url (for source="url")' },
        { status: 400 },
      )
    }

    // Zugriffskontrolle
    if (!userHasAccessToTenant(typedUser, numericTenantId)) {
      await logAccessDenied(
        payload,
        `/api/generate-pdf (tenantId: ${numericTenantId})`,
        typedUser.id,
        user.email as string,
      )

      return NextResponse.json(
        { error: 'Forbidden - You do not have access to this tenant' },
        { status: 403 },
      )
    }

    const rlHeaders = rateLimitHeaders(rateLimit, RATE_LIMIT_MAX)

    // Queued PDF Generation (async)
    if (queued) {
      const queueAvailable = await isQueueAvailable()
      if (!queueAvailable) {
        return NextResponse.json(
          { error: 'Queue system unavailable. Use queued=false for direct generation.' },
          { status: 503, headers: rlHeaders },
        )
      }

      const job = await enqueuePdf({
        tenantId: numericTenantId,
        source,
        html,
        url,
        options,
        documentType,
        filename,
        triggeredBy: String(typedUser.id),
        priority: priority || 'normal',
        correlationId: `pdf-${Date.now()}-${typedUser.id}`,
      })

      return NextResponse.json(
        {
          success: true,
          queued: true,
          message: 'PDF generation job queued successfully',
          jobId: job.id,
        },
        { headers: rlHeaders },
      )
    }

    // Direct PDF Generation (sync)
    let result
    if (source === 'html') {
      result = await generatePdfFromHtml(html, options)
    } else {
      result = await generatePdfFromUrl(url, options)
    }

    if (!result.success) {
      return NextResponse.json(
        { success: false, error: result.error },
        { status: 500, headers: rlHeaders },
      )
    }

    // PDF als Base64 zurückgeben
    return NextResponse.json(
      {
        success: true,
        queued: false,
        pdf: result.buffer?.toString('base64'),
        filename: filename || `document-${Date.now()}.pdf`,
        pageCount: result.pageCount,
        fileSize: result.fileSize,
        duration: result.duration,
      },
      { headers: rlHeaders },
    )
  } catch (error) {
    logger.error('generate-pdf error', error)
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      { status: 500 },
    )
  }
}

/**
 * GET /api/generate-pdf?jobId=...
 *
 * Gibt den Status/das Ergebnis eines PDF-Jobs zurück.
 */
export async function GET(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url)
    const jobId = searchParams.get('jobId')

    // Wenn keine jobId, zeige API-Dokumentation
    if (!jobId) {
      return NextResponse.json({
        endpoint: '/api/generate-pdf',
        methods: {
          POST: {
            description: 'Generate a PDF from HTML or URL',
            authentication: 'Required',
            body: {
              tenantId: 'number (required)',
              source: '"html" | "url" (required)',
              html: 'string (required if source="html")',
              url: 'string (required if source="url")',
              options: {
                format: '"A4" | "A3" | "Letter" | "Legal"',
                landscape: 'boolean',
                margin: '{ top, right, bottom, left }',
                printBackground: 'boolean',
                scale: 'number',
              },
              queued: 'boolean (default: true)',
              documentType: 'string (invoice, report, export, etc.)',
              filename: 'string',
              priority: '"high" | "normal" | "low"',
            },
          },
          GET: {
            description: 'Get status/result of a PDF generation job',
            query: {
              jobId: 'string (required)',
            },
          },
        },
        examples: {
          generateFromHtml: {
            tenantId: 1,
            source: 'html',
            html: '<h1>Hello</h1><p>World</p>',
            options: { format: 'A4' },
            queued: true,
          },
          generateFromUrl: {
            tenantId: 1,
            source: 'url',
            url: 'https://example.com/invoice/123',
            queued: false,
          },
        },
      })
    }

    const payload = await getPayload({ config })

    // Authentifizierung prüfen
    const { user } = await payload.auth({ headers: req.headers })

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized - Login required' }, { status: 401 })
    }

    // Job-Status abrufen
    const status = await getPdfJobStatus(jobId)

    if (!status) {
      return NextResponse.json({ error: 'Job not found' }, { status: 404 })
    }

    // Wenn abgeschlossen, Ergebnis mitliefern
    if (status.state === 'completed' && status.result) {
      return NextResponse.json({
        jobId,
        state: status.state,
        result: status.result,
      })
    }

    return NextResponse.json({
      jobId,
      state: status.state,
      progress: status.progress,
      failedReason: status.failedReason,
    })
  } catch (error) {
    logger.error('generate-pdf status error', error)
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      { status: 500 },
    )
  }
}
