#!/usr/bin/env node
/**
 * DashCaddy Release Webhook Handler
 * Receives push webhooks from Gitea, verifies HMAC signature,
 * and triggers build-release.sh.
 *
 * Usage: node webhook-handler.js
 * Env vars:
 *   WEBHOOK_SECRET — Gitea webhook secret (required)
 *   WEBHOOK_PORT   — Listen port (default: 9090)
 *   BUILD_SCRIPT   — Path to build script (default: /opt/dashcaddy-release/build-release.sh)
 */

const http = require('http');
const crypto = require('crypto');
const { spawn } = require('child_process');
const fs = require('fs');

const PORT = parseInt(process.env.WEBHOOK_PORT || '9090', 10);
const SECRET = process.env.WEBHOOK_SECRET;
const BUILD_SCRIPT = process.env.BUILD_SCRIPT || '/opt/dashcaddy-release/build-release.sh';
const LOG_FILE = '/var/log/dashcaddy-release.log';

if (!SECRET) {
  console.error('WEBHOOK_SECRET environment variable is required');
  process.exit(1);
}

let buildRunning = false;

function log(msg) {
  const line = `[webhook] ${new Date().toISOString()} ${msg}`;
  console.log(line);
  fs.appendFileSync(LOG_FILE, line + '\n');
}

function verifySignature(body, signature) {
  if (!signature) return false;
  const hmac = crypto.createHmac('sha256', SECRET).update(body).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(hmac)
  );
}

function triggerBuild() {
  if (buildRunning) {
    log('Build already in progress, skipping');
    return;
  }
  buildRunning = true;
  log('Triggering build...');

  const child = spawn('bash', [BUILD_SCRIPT], {
    stdio: ['ignore', 'pipe', 'pipe'],
    env: { ...process.env, PATH: process.env.PATH },
  });

  child.stdout.on('data', (data) => {
    const lines = data.toString().trim().split('\n');
    lines.forEach(line => log(`[build] ${line}`));
  });

  child.stderr.on('data', (data) => {
    const lines = data.toString().trim().split('\n');
    lines.forEach(line => log(`[build:err] ${line}`));
  });

  child.on('close', (code) => {
    buildRunning = false;
    if (code === 0) {
      log('Build completed successfully');
    } else {
      log(`Build FAILED with exit code ${code}`);
    }
  });
}

const server = http.createServer((req, res) => {
  // Health check
  if (req.method === 'GET' && req.url === '/health') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'ok', buildRunning }));
    return;
  }

  // Only accept POST to /webhook
  if (req.method !== 'POST' || req.url !== '/webhook') {
    res.writeHead(404);
    res.end('Not found');
    return;
  }

  let body = '';
  req.on('data', chunk => { body += chunk; });
  req.on('end', () => {
    // Verify Gitea HMAC signature
    const sig = req.headers['x-gitea-signature'] || '';
    if (!verifySignature(body, sig)) {
      log('Signature verification FAILED');
      res.writeHead(403);
      res.end('Invalid signature');
      return;
    }

    try {
      const payload = JSON.parse(body);
      const ref = payload.ref || '';
      const branch = ref.replace('refs/heads/', '');

      if (branch !== 'main') {
        log(`Ignoring push to ${branch} (not main)`);
        res.writeHead(200);
        res.end('Ignored (not main branch)');
        return;
      }

      const pusher = payload.pusher?.login || 'unknown';
      const commits = payload.commits?.length || 0;
      log(`Push to main by ${pusher}: ${commits} commit(s)`);

      triggerBuild();

      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ accepted: true }));
    } catch (e) {
      log('Failed to parse webhook payload: ' + e.message);
      res.writeHead(400);
      res.end('Invalid payload');
    }
  });
});

server.listen(PORT, '0.0.0.0', () => {
  log(`Webhook handler listening on 127.0.0.1:${PORT}`);
});
