import axios from 'axios';
import { computeWebhookSignature, verifyWebhookSignature } from '@dbis/integration-foundation';
import { logger } from '../utils/logger';
import { appendOmnlAudit } from './omnl-audit-log';

export type OmnlWebhookPayload = {
  event: string;
  chainId?: number;
  lineId?: string;
  /** Idempotency: `${chainId}-${blockNumber}-${logIndex}` */
  deliveryId?: string;
  payload: Record<string, unknown>;
  ts: string;
};

function parseWebhookUrls(): string[] {
  const raw = process.env.OMNL_WEBHOOK_URLS || '';
  return raw
    .split(',')
    .map((s) => s.trim())
    .filter(Boolean);
}

/** HMAC-SHA256(hex) of UTF-8 body; header value `sha256=<hex>`. */
export function signOmnlWebhookBody(rawBodyUtf8: string, secret: string): string {
  return `sha256=${computeWebhookSignature(secret, rawBodyUtf8)}`;
}

/**
 * Verify `X-OMNL-Signature` from `signOmnlWebhookBody` (timing-safe).
 */
export function verifyOmnlWebhookSignature(
  rawBodyUtf8: string,
  signatureHeader: string | undefined,
  secret: string
): boolean {
  if (!signatureHeader || !secret) return false;
  return verifyWebhookSignature({
    secret,
    payload: rawBodyUtf8,
    signature: signatureHeader.trim(),
  });
}

/**
 * POST JSON to each configured OMNL_WEBHOOK_URLS (comma-separated). Failures are logged, not thrown.
 * Sends `X-OMNL-Signature: sha256=<hmac>` when OMNL_WEBHOOK_SECRET is set (HMAC of exact JSON body bytes).
 */
export async function emitOmnlWebhook(body: OmnlWebhookPayload): Promise<void> {
  const urls = parseWebhookUrls();
  if (urls.length === 0) {
    return;
  }
  const secret = process.env.OMNL_WEBHOOK_SECRET || '';
  const rawBody = JSON.stringify(body);
  const headers: Record<string, string> = {
    'Content-Type': 'application/json; charset=utf-8',
    ...(secret ? { 'X-OMNL-Signature': signOmnlWebhookBody(rawBody, secret) } : {}),
  };
  await Promise.allSettled(
    urls.map(async (url) => {
      try {
        await axios.post(url, rawBody, { timeout: 15000, headers });
        appendOmnlAudit({
          category: 'webhook_out',
          action: 'emit',
          traceId: body.deliveryId,
          metadata: { url, event: body.event, chainId: body.chainId },
          status: 'ok',
        });
      } catch (e) {
        logger.warn(`OMNL webhook failed ${url}`, { error: e instanceof Error ? e.message : String(e) });
        appendOmnlAudit({
          category: 'webhook_out',
          action: 'emit',
          traceId: body.deliveryId,
          metadata: { url, event: body.event },
          status: 'error',
        });
      }
    })
  );
}
