/**
 * Partner Webhook Example (JavaScript)
 *
 * Demonstrates how a payment partner (e.g., Assemble AI, NS3) should
 * structure their webhook payload when notifying Vaultfire of a payment.
 *
 * The webhook endpoint: POST /vaultfire/x402-webhook
 * (provided by x402_listener.py Flask blueprint)
 *
 * HMAC signing is required for third-party rails.
 * Set VAULTFIRE_X402_PARTNER_KEYS_JSON or VAULTFIRE_X402_ASSEMBLE_SECRET
 * in the Vaultfire server environment.
 *
 * Usage:
 *   PARTNER_SECRET=yoursecret node examples/partner-webhook.js
 *
 * Facilitator: https://x402.org/facilitator
 * Hub:         https://theloopbreaker.com
 */

const crypto = require('crypto');
const https = require('https');

// ---------------------------------------------------------------------------
// Configuration
// ---------------------------------------------------------------------------

const VAULTFIRE_WEBHOOK_URL = process.env.VAULTFIRE_WEBHOOK_URL
  || 'https://theloopbreaker.com/vaultfire/x402-webhook';

const PARTNER_SECRET = process.env.PARTNER_SECRET || 'your-partner-secret-from-vaultfire';
const PARTNER_ID = 'assemble';  // or 'ns3'
const KEY_ID = 'k1';            // key rotation identifier

// ---------------------------------------------------------------------------
// HMAC signing helpers
// ---------------------------------------------------------------------------

/**
 * Build the canonical message string for HMAC signing.
 * Must match the canonicalization in x402_receipts.py.
 */
function buildCanonicalMessage(payload) {
  const msg = {
    partner_id: payload.partner_id || null,
    key_id: payload.key_id || 'k1',
    rail: payload.rail || null,
    currency: (payload.currency || '').toUpperCase(),
    amount: payload.amount ?? null,
    wallet_address: payload.wallet_address || null,
    tx_ref: payload.tx_ref || payload.tx_hash || null,
    nonce: payload.nonce || null,
    timestamp: payload.timestamp || null,
  };
  // Sort keys alphabetically to match Python's sort_keys=True
  return JSON.stringify(msg, Object.keys(msg).sort());
}

/**
 * Sign a webhook payload with HMAC-SHA256.
 *
 * @param {object} payload - The payload to sign (must include timestamp and nonce)
 * @param {string} secret  - The shared HMAC secret
 * @returns {string}       - Hex signature
 */
function signPayload(payload, secret) {
  const message = buildCanonicalMessage(payload);
  return crypto.createHmac('sha256', secret).update(message).digest('hex');
}

/**
 * Generate a unique nonce for replay protection.
 */
function generateNonce() {
  return crypto.randomBytes(16).toString('hex');
}

// ---------------------------------------------------------------------------
// Build a signed webhook payload
// ---------------------------------------------------------------------------

/**
 * Create a signed payment webhook payload.
 *
 * @param {object} params
 * @param {string} params.rail           - Payment rail: 'assemble' | 'ns3' | 'evm'
 * @param {string} params.currency       - Currency: 'ASM' | 'ETH' | 'USDC'
 * @param {number} params.amount         - Payment amount
 * @param {string} params.wallet_address - Payer wallet address
 * @param {string} [params.tx_ref]       - Transaction reference
 * @param {number} [params.loyalty_score] - Loyalty score (0.0–1.0)
 */
function createSignedPayload({
  rail,
  currency,
  amount,
  wallet_address,
  tx_ref,
  loyalty_score = 0.0,
}) {
  const timestamp = Date.now() / 1000; // unix seconds
  const nonce = generateNonce();

  const basePayload = {
    type: 'payment',
    status: 'completed',
    rail,
    currency,
    amount,
    wallet_address,
    tx_ref,
    loyalty_score,
    partner_id: PARTNER_ID,
    key_id: KEY_ID,
    nonce,
    timestamp,
    // Ghostkey mode: include a codex signature for wallet verification
    signature: 'codex::partner-webhook',
    // Optional: belief signal for additional verification
    belief_signal: {
      confidence: 0.95,
      source: 'belief-engine',
      verified: true,
    },
  };

  // Sign the payload
  const hmacSignature = signPayload(basePayload, PARTNER_SECRET);

  return {
    ...basePayload,
    signature: hmacSignature, // override codex::partner-webhook with HMAC
  };
}

// ---------------------------------------------------------------------------
// Send webhook to Vaultfire
// ---------------------------------------------------------------------------

/**
 * POST a signed webhook payload to the Vaultfire x402 listener.
 *
 * @param {object} payload - The signed payload to send
 * @returns {Promise<object>} - The server response
 */
function sendWebhook(payload) {
  return new Promise((resolve, reject) => {
    const body = JSON.stringify(payload);
    const url = new URL(VAULTFIRE_WEBHOOK_URL);

    const options = {
      hostname: url.hostname,
      port: url.port || 443,
      path: url.pathname + url.search,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(body),
        'X-Partner-ID': PARTNER_ID,
        'X-Key-ID': KEY_ID,
      },
    };

    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => { data += chunk; });
      res.on('end', () => {
        try {
          resolve({ status: res.statusCode, body: JSON.parse(data) });
        } catch {
          resolve({ status: res.statusCode, body: data });
        }
      });
    });

    req.on('error', reject);
    req.write(body);
    req.end();
  });
}

// ---------------------------------------------------------------------------
// Example: Send an ASM payment webhook from Assemble AI
// ---------------------------------------------------------------------------

async function sendAssemblePaymentWebhook() {
  console.log('=== Vaultfire x402 Partner Webhook Example ===\n');

  const payload = createSignedPayload({
    rail: 'assemble',
    currency: 'ASM',
    amount: 0.00021,
    wallet_address: 'bpow20.cb.id', // ghostkey wallet
    tx_ref: `asm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
    loyalty_score: 0.90,
  });

  console.log('[webhook] Payload to send:');
  console.log(JSON.stringify(payload, null, 2));

  try {
    const response = await sendWebhook(payload);
    console.log(`\n[webhook] Response status: ${response.status}`);
    console.log('[webhook] Response body:', JSON.stringify(response.body, null, 2));

    if (response.body?.airdrop) {
      console.log('\n[webhook] AIRDROP TRIGGERED! 🎉');
      console.log(JSON.stringify(response.body.airdrop, null, 2));
    }
  } catch (err) {
    console.error('[webhook] Error sending webhook:', err.message);
  }
}

// ---------------------------------------------------------------------------
// Example: Verify HMAC signature (server-side validation demo)
// ---------------------------------------------------------------------------

function verifyIncomingWebhook(payload, secret) {
  const receivedSignature = payload.signature;
  const expectedSignature = signPayload(payload, secret);
  const valid = crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(receivedSignature, 'hex'),
  );
  console.log(`\n[verify] Signature valid: ${valid}`);
  return valid;
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

sendAssemblePaymentWebhook();

module.exports = { createSignedPayload, signPayload, generateNonce, sendWebhook };
