import { base64UrlDecodeBytes, base64UrlDecodeStr } from '@/lib/encoding.js';
import { captureCaught } from '@/server/observability/capture.server.js';

// HMAC-SHA-256 signed tokens for one-click unsubscribe URLs.
// Token encodes { userId, action, exp } — signed with JWT_SECRET.

const enc = new TextEncoder();

async function importKey(secret: string): Promise<CryptoKey> {
  return crypto.subtle.importKey(
    'raw',
    enc.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign', 'verify'],
  );
}

export async function signUnsubscribeToken(
  userId: string,
  jwtSecret: string,
  siteUrl: string,
): Promise<string> {
  const payload = JSON.stringify({
    userId,
    action: 'unsubscribe',
    exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 365,
  });
  const key = await importKey(jwtSecret);
  const sig = await crypto.subtle.sign('HMAC', key, enc.encode(payload));
  const sigB64 = btoa(String.fromCharCode(...new Uint8Array(sig)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
  const token =
    btoa(payload).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') + '.' + sigB64;
  return `${siteUrl}/api/unsubscribe?token=${encodeURIComponent(token)}`;
}

export async function verifyUnsubscribeToken(
  token: string,
  jwtSecret: string,
): Promise<{ userId: string } | null> {
  try {
    const [payloadB64, sigB64] = token.split('.');
    if (!payloadB64 || !sigB64) return null;
    const payload = JSON.parse(base64UrlDecodeStr(payloadB64)) as {
      userId: string;
      action: string;
      exp: number;
    };
    if (payload.action !== 'unsubscribe') return null;
    if (payload.exp < Math.floor(Date.now() / 1000)) return null;
    const key = await importKey(jwtSecret);
    const sigBytes = base64UrlDecodeBytes(sigB64);
    const reconstructed = JSON.stringify({
      userId: payload.userId,
      action: 'unsubscribe',
      exp: payload.exp,
    });
    const valid = await crypto.subtle.verify(
      'HMAC',
      key,
      sigBytes as BufferSource,
      enc.encode(reconstructed),
    );
    if (!valid) return null;
    return { userId: payload.userId };
  } catch (err) {
    captureCaught(err, {
      scope: 'server.email.marketing-token.verify',
      severity: 'info',
    });
    return null;
  }
}
