/**
 * Webhook Routes (Gitea etc.)
 * Production: https://emailsorter.webklar.com/api/webhook/gitea
 * POST /api/webhook/gitea - Deployment on push (validates Bearer or X-Gitea-Signature)
 */

import express from 'express'
import crypto from 'crypto'
import { asyncHandler, AuthorizationError } from '../middleware/errorHandler.mjs'
import { config } from '../config/index.mjs'
import { log } from '../middleware/logger.mjs'

const router = express.Router()
const secret = config.gitea.webhookSecret
const authToken = config.gitea.webhookAuthToken

/**
 * Validate Gitea webhook request:
 * - Authorization: Bearer <secret|authToken> (Gitea 1.19+ or manual calls)
 * - X-Gitea-Signature: HMAC-SHA256 hex of raw body (Gitea default)
 */
function validateGiteaWebhook(req) {
  const rawBody = req.body
  if (!rawBody || !Buffer.isBuffer(rawBody)) {
    throw new AuthorizationError('Raw body fehlt (Webhook-Route muss vor JSON-Parser registriert sein)')
  }

  // 1) Bearer token (Header)
  const authHeader = req.get('Authorization')
  if (authHeader && authHeader.startsWith('Bearer ')) {
    const token = authHeader.slice(7).trim()
    const expected = authToken || secret
    if (expected && token === expected) {
      return true
    }
  }

  // 2) X-Gitea-Signature (HMAC-SHA256 hex)
  const signatureHeader = req.get('X-Gitea-Signature')
  if (signatureHeader && secret) {
    try {
      const expectedHex = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
      const received = signatureHeader.trim()
      const receivedHex = received.startsWith('sha256=') ? received.slice(7) : received
      if (expectedHex.length === receivedHex.length && expectedHex.length > 0) {
        const a = Buffer.from(expectedHex, 'hex')
        const b = Buffer.from(receivedHex, 'hex')
        if (a.length === b.length && crypto.timingSafeEqual(a, b)) return true
      }
    } catch (_) {
      // invalid hex or comparison error – fall through to reject
    }
  }

  if (!secret && !authToken) {
    throw new AuthorizationError('GITEA_WEBHOOK_SECRET nicht konfiguriert')
  }
  throw new AuthorizationError('Ungültige Webhook-Signatur oder fehlender Authorization-Header')
}

/**
 * POST /api/webhook/gitea
 * Gitea push webhook – validates Bearer or X-Gitea-Signature, then accepts event
 */
router.post('/gitea', asyncHandler(async (req, res) => {
  try {
    validateGiteaWebhook(req)
  } catch (err) {
    // AuthorizationError uses statusCode 403, not 401 — do not rely on err.name (can be wrong on some engines)
    if (err instanceof AuthorizationError) throw err
    log.error('Gitea Webhook: Validierung fehlgeschlagen', { error: err.message })
    return res.status(401).json({ error: 'Webhook validation failed' })
  }

  let payload
  try {
    const raw = req.body && typeof req.body.toString === 'function' ? req.body.toString('utf8') : ''
    payload = raw ? JSON.parse(raw) : {}
  } catch (e) {
    log.warn('Gitea Webhook: ungültiges JSON', { error: e.message })
    return res.status(400).json({ error: 'Invalid JSON body' })
  }

  const ref = payload.ref || ''
  const branch = ref.replace(/^refs\/heads\//, '')
  const event = req.get('X-Gitea-Event') || 'push'
  log.info('Gitea Webhook empfangen', { ref, branch, event })

  // Optional: trigger deploy script in background (do not block response)
  setImmediate(async () => {
    try {
      const { spawn } = await import('child_process')
      const { fileURLToPath } = await import('url')
      const { dirname, join } = await import('path')
      const { existsSync } = await import('fs')
      const __dirname = dirname(fileURLToPath(import.meta.url))
      const deployScript = join(__dirname, '..', '..', 'scripts', 'deploy-to-server.mjs')
      if (existsSync(deployScript)) {
        const child = spawn('node', [deployScript], {
          cwd: join(__dirname, '..', '..'),
          stdio: ['ignore', 'pipe', 'pipe'],
          detached: true,
        })
        child.unref()
        child.stdout?.on('data', (d) => log.info('Deploy stdout:', d.toString().trim()))
        child.stderr?.on('data', (d) => log.warn('Deploy stderr:', d.toString().trim()))
      }
    } catch (_) {}
  })

  res.status(202).json({ received: true, ref, branch })
}))

/**
 * GET /api/webhook/status
 * Simple status for webhook endpoint (e.g. health check)
 */
router.get('/status', (req, res) => {
  res.json({
    ok: true,
    webhook: 'gitea',
    configured: Boolean(secret || authToken),
  })
})

export default router
