import * as crypto from 'crypto';
import {
  ZOOM_ANALYTICS_WEBHOOK_HMAC,
  ZOOM_ANALYTICS_WEBHOOK_MAX_AGE_SECONDS,
} from '../constants/zoom-analytics.constants';

export interface ZoomAnalyticsUrlValidationResponse {
  plainToken: string;
  encryptedToken: string;
}

/**
 * HMAC verification for the new analytics webhook, per Zoom's own documented
 * scheme: the message is built over `JSON.stringify(body)` using the body
 * Express already parsed (preserves the original key order/content) — NOT a
 * re-serialized DTO, which Nest's whitelisting ValidationPipe would
 * strip/reorder and break the match. Self-contained; not used by (and does
 * not touch) any existing Zoom webhook code — there is none today.
 */
export class ZoomAnalyticsWebhookSignatureUtil {
  static buildUrlValidationResponse(plainToken: string, secret: string): ZoomAnalyticsUrlValidationResponse {
    return {
      plainToken,
      encryptedToken: crypto
        .createHmac(ZOOM_ANALYTICS_WEBHOOK_HMAC.ALGORITHM, secret)
        .update(plainToken)
        .digest(ZOOM_ANALYTICS_WEBHOOK_HMAC.ENCODING),
    };
  }

  static verifySignature(body: unknown, signature: string | undefined, timestamp: string | undefined, secret: string): boolean {
    if (!signature || !timestamp) return false;
    const message = `${ZOOM_ANALYTICS_WEBHOOK_HMAC.MESSAGE_PREFIX}:${timestamp}:${JSON.stringify(body)}`;
    const expected = `${ZOOM_ANALYTICS_WEBHOOK_HMAC.SIGNATURE_PREFIX}${crypto
      .createHmac(ZOOM_ANALYTICS_WEBHOOK_HMAC.ALGORITHM, secret)
      .update(message)
      .digest(ZOOM_ANALYTICS_WEBHOOK_HMAC.ENCODING)}`;
    try {
      return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
    } catch {
      return false; // length mismatch etc. — definitely not a valid signature
    }
  }

  static isTimestampFresh(timestamp: string | undefined): boolean {
    if (!timestamp) return false;
    const ts = Number(timestamp);
    if (!Number.isFinite(ts)) return false;
    const ageSeconds = Math.abs(Date.now() / 1000 - ts);
    return ageSeconds <= ZOOM_ANALYTICS_WEBHOOK_MAX_AGE_SECONDS;
  }
}
