// Supabase Send-Email-Hook receiver.
//
// GoTrue (v2.155+) postet hier rein wenn Mail-Versand getriggert wird
// (signup/recovery/magiclink/invite/email_change). Wir rendern selbst +
// senden via Brevo Transactional API — Vorteil: dynamic Sender-Name +
// Subject pro Mail-Typ × User-Locale (GoTrue's eingebauter Mailer ist
// global statisch).
//
// Config (im Compose): GOTRUE_HOOK_SEND_EMAIL_ENABLED=true,
// GOTRUE_HOOK_SEND_EMAIL_URI auf diesen Endpoint,
// GOTRUE_HOOK_SEND_EMAIL_SECRETS=v1,whsec_<base64>
//
// Verifikation: Standard-Webhooks-Signatur (HMAC-SHA256).

import { createHmac, timingSafeEqual } from 'node:crypto';
import {
  renderEmail,
  normalizeLocale,
  type EmailActionType,
} from '../../utils/mail/templates';
import { sendBrevoMail } from '../../utils/mail/brevo';

interface HookBody {
  user: {
    id: string;
    email: string;
    user_metadata?: { locale?: string | null } | null;
  };
  email_data: {
    token: string;
    token_hash?: string;
    redirect_to?: string;
    email_action_type: string;
    site_url?: string;
  };
}

function verifySignature(
  webhookId: string,
  webhookTimestamp: string,
  rawBody: string,
  signatureHeader: string,
  secretsCsv: string,
): boolean {
  // secretsCsv can have multiple comma-separated entries "v1,whsec_X,v1,whsec_Y"
  // Pairs: ["v1", "whsec_X"], ["v1", "whsec_Y"]
  const parts = secretsCsv.split(',').map((s) => s.trim());
  const secrets: string[] = [];
  for (let i = 0; i + 1 < parts.length; i += 2) {
    if (parts[i] === 'v1' && parts[i + 1].startsWith('whsec_')) {
      secrets.push(parts[i + 1].slice(6));
    }
  }
  if (secrets.length === 0) return false;

  const signedContent = `${webhookId}.${webhookTimestamp}.${rawBody}`;

  // signatureHeader format: "v1,BASE64 [v1,BASE64 ...]"
  const headerSigs = signatureHeader
    .split(' ')
    .map((s) => s.split(','))
    .filter((pair) => pair[0] === 'v1' && pair[1])
    .map((pair) => pair[1]);

  for (const secret of secrets) {
    const secretBytes = Buffer.from(secret, 'base64');
    const expected = createHmac('sha256', secretBytes)
      .update(signedContent)
      .digest();

    for (const headerSig of headerSigs) {
      try {
        const received = Buffer.from(headerSig, 'base64');
        if (
          received.length === expected.length &&
          timingSafeEqual(received, expected)
        ) {
          return true;
        }
      } catch {
        // malformed base64, skip
      }
    }
  }
  return false;
}

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig(event);

  // Read raw body for HMAC verification (must hash exact bytes GoTrue sent)
  const rawBody = await readRawBody(event, 'utf8');
  if (!rawBody) {
    throw createError({ statusCode: 400, message: 'empty body' });
  }

  const webhookId = getHeader(event, 'webhook-id');
  const webhookTimestamp = getHeader(event, 'webhook-timestamp');
  const webhookSignature = getHeader(event, 'webhook-signature');
  const secretsCsv = (config.hookSendEmailSecrets as string) || '';

  if (!webhookId || !webhookTimestamp || !webhookSignature) {
    throw createError({
      statusCode: 400,
      message: 'missing webhook-* headers',
    });
  }
  if (!secretsCsv) {
    throw createError({
      statusCode: 500,
      message: 'hookSendEmailSecrets not configured',
    });
  }

  const ok = verifySignature(
    webhookId,
    webhookTimestamp,
    rawBody,
    webhookSignature,
    secretsCsv,
  );
  if (!ok) {
    throw createError({ statusCode: 401, message: 'invalid signature' });
  }

  const payload = JSON.parse(rawBody) as HookBody;
  const action = payload.email_data.email_action_type as EmailActionType;
  const validActions: EmailActionType[] = [
    'signup',
    'recovery',
    'magiclink',
    'invite',
    'email_change',
  ];
  if (!validActions.includes(action)) {
    console.warn(
      `[auth-hook/send-email] unknown action=${action}, falling back to signup`,
    );
  }

  const locale = normalizeLocale(payload.user.user_metadata?.locale);
  const rendered = renderEmail(
    validActions.includes(action) ? action : 'signup',
    locale,
    payload.email_data.token,
  );

  const senderEmail = (config.mailSenderEmail as string) || 'welcome@rebreak.org';

  await sendBrevoMail(event, {
    to: payload.user.email,
    subject: rendered.subject,
    senderName: rendered.senderName,
    senderEmail,
    htmlContent: rendered.html,
  });

  console.log(
    `[auth-hook/send-email] sent action=${action} locale=${locale} to=${payload.user.email}`,
  );

  return {};
});
