import { createHmac } from "node:crypto";

const PORT = process.env.PORT || "3100";
const BASE = process.env.BASE_URL || `http://127.0.0.1:${PORT}`;
const ADMIN_TOKEN = process.env.ADMIN_TOKEN || "admin-dev-token";
const MERCHANT_TOKEN = process.env.MERCHANT_TOKEN || "merchant-dev-token";
const MERCHANT_PORTAL_PASSWORD = process.env.MERCHANT_PORTAL_PASSWORD || "merchant";
const DEVICE_TOKEN = process.env.DEVICE_TOKEN || "device-dev-token";
const SECRET = process.env.INTEGRATION_WEBHOOK_SECRET || "dev-callback-secret";

function short(data) {
  const json = typeof data === 'string' ? data : JSON.stringify(data || {});
  return json.length > 180 ? `${json.slice(0, 180)}...` : json;
}

async function req(path, options = {}) {
  const response = await fetch(`${BASE}${path}`, {
    method: options.method || 'GET',
    headers: {
      'Content-Type': 'application/json',
      ...(options.headers || {})
    },
    body: Object.prototype.hasOwnProperty.call(options, 'body') ? JSON.stringify(options.body) : undefined
  });

  const text = await response.text();
  let body = null;
  try {
    body = text ? JSON.parse(text) : null;
  } catch {
    body = text;
  }

  if (!response.ok) {
    throw new Error(`${options._label || path} failed: ${response.status}`);
  }

  console.log(`${options._label || `${options.method || 'GET'} ${path}`} => ${response.status} ${short(body)}`);
  return body;
}

async function reqExpect(path, expectedStatus, options = {}) {
  const response = await fetch(`${BASE}${path}`, {
    method: options.method || 'GET',
    headers: {
      'Content-Type': 'application/json',
      ...(options.headers || {})
    },
    body: Object.prototype.hasOwnProperty.call(options, 'body') ? JSON.stringify(options.body) : undefined
  });

  const text = await response.text();
  let body = null;
  try {
    body = text ? JSON.parse(text) : null;
  } catch {
    body = text;
  }

  if (response.status !== expectedStatus) {
    throw new Error(`${options._label || path} expected ${expectedStatus}, got ${response.status}`);
  }

  console.log(`${options._label || `${options.method || 'GET'} ${path}`} => ${response.status} ${short(body)}`);
  return body;
}

async function reqAdmin(path, opts = {}) {
  return req(path, { ...opts, headers: { ...(opts.headers || {}), Authorization: `Bearer ${ADMIN_TOKEN}` } });
}

async function reqMerchant(path, merchantId, opts = {}) {
  return req(path, {
    ...opts,
    headers: {
      ...(opts.headers || {}),
      Authorization: `Bearer ${MERCHANT_TOKEN}`,
      'X-Merchant-Id': merchantId
    }
  });
}

async function reqDevice(path, opts = {}) {
  return req(path, { ...opts, headers: { ...(opts.headers || {}), Authorization: `Bearer ${DEVICE_TOKEN}` } });
}

async function reqDeviceCredential(path, deviceId, secret, opts = {}) {
  return req(path, {
    ...opts,
    headers: {
      ...(opts.headers || {}),
      'X-Device-Id': deviceId,
      'X-Device-Secret': secret
    }
  });
}

(async () => {
  await req('/health', { _label: 'GET /health' });
  await req('/admin/login', { method: 'POST', body: { username: 'admin', password: 'admin' }, _label: 'POST /admin/login' });

  await reqAdmin('/admin/seed/status', { _label: 'GET /admin/seed/status' });
  const ts = Date.now();

  const merchant = await reqAdmin('/admin/merchants', {
    method: 'POST',
    body: {
      legal_name: `Smoke Merchant ${ts}`,
      brand_name: `SMK-${ts}`,
      settlement_account_reference: `bank:${ts}`,
      settlement_account_type: 'merchant_bank_account',
      payout_mode: 'merchant_direct'
    },
    _label: 'POST /admin/merchants'
  });

  const merchantId = merchant?.data?.id;
  const outlet = await reqAdmin(`/admin/merchants/${merchantId}/outlets`, {
    method: 'POST',
    body: { name: `Outlet ${ts}` },
    _label: 'POST /admin/merchants/:id/outlets'
  });

  const outletId = outlet?.data?.id;
  const terminal = await reqAdmin(`/admin/outlets/${outletId}/terminals`, {
    method: 'POST',
    body: { terminal_code: `TERM-${ts}`, qr_mode: 'static' },
    _label: 'POST /admin/outlets/:id/terminals'
  });

  const terminalId = terminal?.data?.id;
  const device = await reqAdmin('/admin/devices', {
    method: 'POST',
    body: {
      device_code: `DEV-${ts}`,
      vendor: 'acme',
      model: 'v1',
      communication_mode: 'mqtt',
      status: 'active'
    },
    _label: 'POST /admin/devices'
  });

  const deviceId = device?.data?.id;
  await reqAdmin(`/admin/devices/${deviceId}/bind`, {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      outlet_id: outletId,
      terminal_id: terminalId
    },
    _label: 'POST /admin/devices/:id/bind'
  });

  await reqDevice('/device/heartbeat', {
    method: 'POST',
    body: {
      device_id: deviceId,
      timestamp: new Date().toISOString(),
      firmware_version: '1.2.3',
      network_strength: 88,
      battery_level: 77,
      state: 'idle'
    },
    _label: 'POST /device/heartbeat'
  });

  const credential = await reqAdmin(`/admin/devices/${deviceId}/credentials/rotate`, {
    method: 'POST',
    body: {},
    _label: 'POST /admin/devices/:id/credentials/rotate'
  });
  const deviceSecret = credential?.data?.credential?.mqtt_password;
  if (!deviceSecret) {
    throw new Error('device credential rotate did not return one-time password');
  }
  await reqDeviceCredential('/device/heartbeat', deviceId, deviceSecret, {
    method: 'POST',
    body: {
      device_id: deviceId,
      timestamp: new Date().toISOString(),
      firmware_version: '1.2.4',
      network_strength: 89,
      battery_level: 76,
      state: 'credential-auth'
    },
    _label: 'POST /device/heartbeat credential auth'
  });

  const tx = await reqAdmin('/admin/transactions', {
    method: 'POST',
    body: {
      partner_reference: `PR-${ts}`,
      merchant_id: merchantId,
      outlet_id: outletId,
      terminal_id: terminalId,
      device_id: deviceId,
      amount: 19900,
      currency: 'IDR',
      qr_mode: 'static',
      initiation_mode: 'static',
      status: 'initiated'
    },
    _label: 'POST /admin/transactions'
  });

  const txId = tx?.data?.id;
  const callback = {
    partner_reference: `PR-${ts}`,
    partner_txn_id: `PTX-${ts}`,
    amount: 19900,
    currency: 'IDR',
    payment_status: 'paid',
    status: 'paid',
    paid_at: new Date().toISOString()
  };
  const signature = createHmac('sha256', SECRET).update(JSON.stringify(callback)).digest('hex');

  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': signature },
    body: { ...callback, signature },
    _label: 'POST /integrations/qris/callback'
  });

  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': signature },
    body: { ...callback, signature },
    _label: 'POST /integrations/qris/callback duplicate'
  });

  await reqExpect('/integrations/qris/callback', 401, {
    method: 'POST',
    headers: { 'X-Partner-Signature': 'bad-signature' },
    body: { ...callback, signature: 'bad-signature' },
    _label: 'POST /integrations/qris/callback invalid signature'
  });

  await reqAdmin(`/admin/transactions/${txId}`, { _label: 'GET /admin/transactions/:id' });
  await reqAdmin(`/admin/transactions/${txId}/events`, { _label: 'GET /admin/transactions/:id/events' });
  await reqAdmin(`/admin/ledger-entries?transaction_id=${txId}`, { _label: 'GET /admin/ledger-entries' });
  const settlementBatchCreate = await reqAdmin('/admin/settlement-batches', {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      cutoff_at: new Date().toISOString()
    },
    _label: 'POST /admin/settlement-batches'
  });
  const settlementBatch = settlementBatchCreate?.data?.batches?.[0];
  if (!settlementBatch || settlementBatch.entry_count < 1 || Number(settlementBatch.net_payable_amount) <= 0) {
    throw new Error('settlement batch did not include merchant payable entries');
  }
  await reqAdmin('/admin/settlement-batches?status=created', { _label: 'GET /admin/settlement-batches' });
  await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}`, { _label: 'GET /admin/settlement-batches/:id' });
  const settlementCsv = await req(`/admin/settlement-batches/${settlementBatch.id}/export.csv`, {
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    _label: 'GET /admin/settlement-batches/:id/export.csv'
  });
  if (!String(settlementCsv).includes('batch_code,batch_status,merchant_id')) {
    throw new Error('settlement CSV export missing expected header');
  }
  const settlementBankCsv = await req(`/admin/settlement-batches/${settlementBatch.id}/export.csv?format=bank_generic`, {
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    _label: 'GET /admin/settlement-batches/:id/export.csv bank_generic'
  });
  if (!String(settlementBankCsv).includes('transfer_type,beneficiary_account_reference,beneficiary_account_type')) {
    throw new Error('settlement bank generic CSV export missing expected header');
  }
  await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}/mark-paid`, {
    method: 'POST',
    body: {
      paid_at: new Date().toISOString(),
      paid_reference: `SMOKE-PAYOUT-${ts}`,
      paid_note: 'Smoke payout reconciliation note'
    },
    _label: 'POST /admin/settlement-batches/:id/mark-paid'
  });
  const settlementDetailWithEvents = await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id events'
  });
  const settlementEvents = settlementDetailWithEvents?.data?.events || [];
  if (!settlementEvents.some((event) => event.event_type === 'created') || !settlementEvents.some((event) => event.event_type === 'marked_paid')) {
    throw new Error('settlement payout event history missing created or marked_paid event');
  }
  await reqExpect(`/admin/settlement-batches/${settlementBatch.id}/mark-paid`, 409, {
    method: 'POST',
    body: {},
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    _label: 'POST /admin/settlement-batches/:id/mark-paid duplicate'
  });
  await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}/reference`, {
    method: 'PATCH',
    body: {
      paid_reference: `SMOKE-PAYOUT-UPDATED-${ts}`,
      paid_note: 'Smoke payout reference correction'
    },
    _label: 'PATCH /admin/settlement-batches/:id/reference'
  });
  const settlementDetailAfterReference = await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id reference-updated'
  });
  if (
    settlementDetailAfterReference?.data?.batch?.metadata_json?.paid_reference !== `SMOKE-PAYOUT-UPDATED-${ts}` ||
    !settlementDetailAfterReference?.data?.events?.some((event) => event.event_type === 'reference_updated')
  ) {
    throw new Error('settlement reference update did not persist metadata or event history');
  }
  await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}/adjustments`, {
    method: 'POST',
    body: {
      adjustment_type: 'debit',
      amount: 100,
      reason: 'Smoke reconciliation fee correction',
      note: 'Smoke adjustment event'
    },
    _label: 'POST /admin/settlement-batches/:id/adjustments'
  });
  const settlementDetailAfterAdjustment = await reqAdmin(`/admin/settlement-batches/${settlementBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id adjustment-recorded'
  });
  if (
    Number(settlementDetailAfterAdjustment?.data?.batch?.metadata_json?.total_adjustment_amount || 0) !== -100 ||
    !Array.isArray(settlementDetailAfterAdjustment?.data?.adjustments) ||
    settlementDetailAfterAdjustment.data.adjustments.length < 1 ||
    Number(settlementDetailAfterAdjustment.data.adjustments[0]?.signed_amount || 0) !== -100 ||
    !settlementDetailAfterAdjustment?.data?.events?.some((event) => event.event_type === 'adjustment_recorded')
  ) {
    throw new Error('settlement adjustment did not persist metadata or event history');
  }
  const settlementAdjustmentReport = await reqAdmin(`/admin/settlement-adjustments?merchant_id=${merchantId}&limit=20`, {
    _label: 'GET /admin/settlement-adjustments'
  });
  if (
    !Array.isArray(settlementAdjustmentReport?.data?.rows) ||
    settlementAdjustmentReport.data.rows.length < 1 ||
    Number(settlementAdjustmentReport.data.signed_amount || 0) !== -100 ||
    !settlementAdjustmentReport.data.rows.some((row) => row.batch_id === settlementBatch.id && Number(row.signed_amount || 0) === -100)
  ) {
    throw new Error('settlement adjustment report missing expected row or totals');
  }
  const settlementAdjustmentCsv = await req(`/admin/settlement-adjustments/export.csv?merchant_id=${merchantId}&limit=20`, {
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    _label: 'GET /admin/settlement-adjustments/export.csv'
  });
  if (
    !String(settlementAdjustmentCsv).includes('adjustment_id,batch_id,batch_code') ||
    !String(settlementAdjustmentCsv).includes('Smoke reconciliation fee correction')
  ) {
    throw new Error('settlement adjustment CSV export missing expected header or row');
  }
  const merchantLogin = await req('/merchant/login', {
    method: 'POST',
    body: { username: merchantId, password: MERCHANT_PORTAL_PASSWORD },
    _label: 'POST /merchant/login'
  });
  if (merchantLogin?.data?.merchant?.id !== merchantId || !merchantLogin?.data?.token) {
    throw new Error('merchant login did not return expected merchant session');
  }
  const merchantSummary = await reqMerchant('/merchant/settlement-summary', merchantId, {
    _label: 'GET /merchant/settlement-summary'
  });
  const merchantPaidAmount = Number(merchantSummary?.data?.paid_amount || 0);
  const merchantAdjustmentAmount = Number(merchantSummary?.data?.adjustment_amount || 0);
  const merchantAdjustedPaidAmount = Number(merchantSummary?.data?.adjusted_paid_amount || 0);
  if (
    merchantPaidAmount < Number(settlementBatch.net_payable_amount || 0) ||
    merchantAdjustmentAmount !== -100 ||
    Math.abs(merchantAdjustedPaidAmount - (merchantPaidAmount - 100)) > 0.01
  ) {
    throw new Error('merchant settlement summary missing paid amount');
  }
  await reqMerchant('/merchant/settlement-batches', merchantId, {
    _label: 'GET /merchant/settlement-batches'
  });
  const merchantBatchDetail = await reqMerchant(`/merchant/settlement-batches/${settlementBatch.id}`, merchantId, {
    _label: 'GET /merchant/settlement-batches/:id'
  });
  if (!merchantBatchDetail?.data?.events?.some((event) => event.event_type === 'marked_paid')) {
    throw new Error('merchant settlement batch detail missing payout event history');
  }
  if (!Array.isArray(merchantBatchDetail?.data?.adjustments) || merchantBatchDetail.data.adjustments.length < 1) {
    throw new Error('merchant settlement batch detail missing formal adjustment rows');
  }
  const merchantSettlementCsv = await req(`/merchant/settlement-batches/${settlementBatch.id}/export.csv`, {
    headers: { Authorization: `Bearer ${MERCHANT_TOKEN}`, 'X-Merchant-Id': merchantId },
    _label: 'GET /merchant/settlement-batches/:id/export.csv'
  });
  if (!String(merchantSettlementCsv).includes('batch_code,batch_status,merchant_id')) {
    throw new Error('merchant settlement CSV export missing expected header');
  }
  const merchantSettlementBankCsv = await req(`/merchant/settlement-batches/${settlementBatch.id}/export.csv?format=bank_generic`, {
    headers: { Authorization: `Bearer ${MERCHANT_TOKEN}`, 'X-Merchant-Id': merchantId },
    _label: 'GET /merchant/settlement-batches/:id/export.csv bank_generic'
  });
  if (!String(merchantSettlementBankCsv).includes('transfer_type,beneficiary_account_reference,beneficiary_account_type')) {
    throw new Error('merchant settlement bank generic CSV export missing expected header');
  }
  await reqAdmin(`/admin/audit-logs?entity_id=${txId}`, { _label: 'GET /admin/audit-logs' });
  await reqAdmin(`/admin/transactions/${txId}/heartbeats`, { _label: 'GET /admin/transactions/:id/heartbeats' });
  await reqAdmin(`/admin/devices/${deviceId}/heartbeats`, { _label: 'GET /admin/devices/:id/heartbeats' });
  await reqAdmin(`/admin/devices/${deviceId}`, { _label: 'GET /admin/devices/:id health summary' });
  await reqAdmin('/admin/notifications/failed', { _label: 'GET /admin/notifications/failed' });
  await reqAdmin(`/admin/transactions/${txId}/retry-notification`, {
    method: 'POST',
    body: {},
    _label: 'POST /admin/transactions/:id/retry-notification'
  });
  const dashboardSummary = await reqAdmin('/admin/dashboard/summary', { _label: 'GET /admin/dashboard/summary' });
  const dashboardData = dashboardSummary?.data || {};
  const dashboardPaidAmount = Number(dashboardData.settlement_paid_amount || 0);
  const dashboardAdjustmentAmount = Number(dashboardData.settlement_adjustment_amount || 0);
  const dashboardAdjustedPaidAmount = Number(dashboardData.settlement_adjusted_paid_amount || 0);
  if (
    dashboardPaidAmount < Number(settlementBatch.net_payable_amount || 0) ||
    dashboardAdjustmentAmount !== -100 ||
    Math.abs(dashboardAdjustedPaidAmount - (dashboardPaidAmount - 100)) > 0.01 ||
    Number(dashboardData.settlement_paid_batches || 0) < 1 ||
    Number(dashboardData.settlement_total_batches || 0) < 1
  ) {
    throw new Error('dashboard settlement finance summary missing paid settlement aggregate');
  }

  const noBindingOutlet = await reqAdmin(`/admin/merchants/${merchantId}/outlets`, {
    method: 'POST',
    body: { name: `No Binding Outlet ${ts}` },
    _label: 'POST /admin/merchants/:id/outlets no-binding'
  });
  const noBindingOutletId = noBindingOutlet?.data?.id;
  const noBindingTerminal = await reqAdmin(`/admin/outlets/${noBindingOutletId}/terminals`, {
    method: 'POST',
    body: { terminal_code: `TERM-NB-${ts}`, qr_mode: 'static' },
    _label: 'POST /admin/outlets/:id/terminals no-binding'
  });
  const noBindingTerminalId = noBindingTerminal?.data?.id;
  const noBindingTx = await reqAdmin('/admin/transactions', {
    method: 'POST',
    body: {
      partner_reference: `PR-NB-${ts}`,
      merchant_id: merchantId,
      outlet_id: noBindingOutletId,
      terminal_id: noBindingTerminalId,
      amount: 9900,
      currency: 'IDR',
      qr_mode: 'static',
      initiation_mode: 'static',
      status: 'initiated'
    },
    _label: 'POST /admin/transactions no-binding'
  });
  const noBindingCallback = {
    partner_reference: `PR-NB-${ts}`,
    partner_txn_id: `PTX-NB-${ts}`,
    amount: 9900,
    currency: 'IDR',
    payment_status: 'paid',
    status: 'paid',
    paid_at: new Date().toISOString()
  };
  const noBindingSignature = createHmac('sha256', SECRET).update(JSON.stringify(noBindingCallback)).digest('hex');
  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': noBindingSignature },
    body: { ...noBindingCallback, signature: noBindingSignature },
    _label: 'POST /integrations/qris/callback no-binding'
  });
  await reqAdmin(`/admin/ledger-entries?transaction_id=${noBindingTx?.data?.id}`, {
    _label: 'GET /admin/ledger-entries no-binding'
  });
  await reqAdmin('/admin/notifications/failed', { _label: 'GET /admin/notifications/failed no-binding' });
  const failedBatchCreate = await reqAdmin('/admin/settlement-batches', {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      cutoff_at: new Date().toISOString()
    },
    _label: 'POST /admin/settlement-batches failed-case'
  });
  const failedBatch = failedBatchCreate?.data?.batches?.[0];
  if (!failedBatch) {
    throw new Error('failed settlement case did not create a batch');
  }
  await reqAdmin(`/admin/settlement-batches/${failedBatch.id}/mark-failed`, {
    method: 'POST',
    body: {
      reason: 'Smoke payout rail rejected transfer',
      note: 'Smoke failed settlement lifecycle'
    },
    _label: 'POST /admin/settlement-batches/:id/mark-failed'
  });
  const failedBatchDetail = await reqAdmin(`/admin/settlement-batches/${failedBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id failed'
  });
  if (
    failedBatchDetail?.data?.batch?.status !== 'failed' ||
    !failedBatchDetail?.data?.events?.some((event) => event.event_type === 'failed')
  ) {
    throw new Error('settlement failed lifecycle did not persist failed status/event');
  }
  const reprocessedFailed = await reqAdmin(`/admin/settlement-batches/${failedBatch.id}/reprocess`, {
    method: 'POST',
    body: {},
    _label: 'POST /admin/settlement-batches/:id/reprocess failed'
  });
  const reprocessedFailedBatch = reprocessedFailed?.data?.new_batch;
  if (!reprocessedFailedBatch || reprocessedFailedBatch.status !== 'created') {
    throw new Error('failed settlement reprocess did not create a new created batch');
  }
  const reprocessedFailedSource = await reqAdmin(`/admin/settlement-batches/${failedBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id reprocessed-source'
  });
  if (!reprocessedFailedSource?.data?.events?.some((event) => event.event_type === 'reprocessed')) {
    throw new Error('failed settlement reprocess did not create source reprocessed event');
  }
  await reqExpect(`/admin/settlement-batches/${failedBatch.id}/reprocess`, 409, {
    method: 'POST',
    body: {},
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    _label: 'POST /admin/settlement-batches/:id/reprocess duplicate'
  });

  const cancelTx = await reqAdmin('/admin/transactions', {
    method: 'POST',
    body: {
      partner_reference: `PR-CANCEL-${ts}`,
      merchant_id: merchantId,
      outlet_id: outletId,
      terminal_id: terminalId,
      amount: 7700,
      currency: 'IDR',
      qr_mode: 'static',
      initiation_mode: 'static',
      status: 'initiated'
    },
    _label: 'POST /admin/transactions cancel-settlement'
  });
  const cancelCallback = {
    partner_reference: `PR-CANCEL-${ts}`,
    partner_txn_id: `PTX-CANCEL-${ts}`,
    amount: 7700,
    currency: 'IDR',
    payment_status: 'paid',
    status: 'paid',
    paid_at: new Date().toISOString()
  };
  const cancelSignature = createHmac('sha256', SECRET).update(JSON.stringify(cancelCallback)).digest('hex');
  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': cancelSignature },
    body: { ...cancelCallback, signature: cancelSignature },
    _label: 'POST /integrations/qris/callback cancel-settlement'
  });
  const cancelBatchCreate = await reqAdmin('/admin/settlement-batches', {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      cutoff_at: new Date().toISOString()
    },
    _label: 'POST /admin/settlement-batches cancel-case'
  });
  const cancelBatch = cancelBatchCreate?.data?.batches?.[0];
  if (!cancelBatch) {
    throw new Error('cancel settlement case did not create a batch');
  }
  await reqAdmin(`/admin/settlement-batches/${cancelBatch.id}/cancel`, {
    method: 'POST',
    body: {
      reason: 'Smoke duplicate manual payout batch',
      note: `cancel tx ${cancelTx?.data?.id}`
    },
    _label: 'POST /admin/settlement-batches/:id/cancel'
  });
  const cancelBatchDetail = await reqAdmin(`/admin/settlement-batches/${cancelBatch.id}`, {
    _label: 'GET /admin/settlement-batches/:id cancelled'
  });
  if (
    cancelBatchDetail?.data?.batch?.status !== 'cancelled' ||
    !cancelBatchDetail?.data?.events?.some((event) => event.event_type === 'cancelled')
  ) {
    throw new Error('settlement cancel lifecycle did not persist cancelled status/event');
  }
  const reconciliationReport = await reqAdmin('/admin/reconciliation/settlement-batches?limit=50', {
    _label: 'GET /admin/reconciliation/settlement-batches'
  });
  const reconciliationData = reconciliationReport?.data || {};
  if (
    !Array.isArray(reconciliationData.rows) ||
    !Number.isFinite(Number(reconciliationData.total_batches)) ||
    !Number.isFinite(Number(reconciliationData.mismatch_batches)) ||
    Number(reconciliationData.total_batches) < 1
  ) {
    throw new Error('settlement reconciliation report missing expected aggregate rows');
  }

  const dynamicOutlet = await reqAdmin(`/admin/merchants/${merchantId}/outlets`, {
    method: 'POST',
    body: { name: `Dynamic API Outlet ${ts}` },
    _label: 'POST /admin/merchants/:id/outlets dynamic-api'
  });
  const dynamicOutletId = dynamicOutlet?.data?.id;
  const dynamicTerminal = await reqAdmin(`/admin/outlets/${dynamicOutletId}/terminals`, {
    method: 'POST',
    body: { terminal_code: `TERM-DYN-${ts}`, qr_mode: 'dynamic_api' },
    _label: 'POST /admin/outlets/:id/terminals dynamic-api'
  });
  const dynamicTerminalId = dynamicTerminal?.data?.id;
  const dynamicDevice = await reqAdmin('/admin/devices', {
    method: 'POST',
    body: {
      device_code: `DEV-API-${ts}`,
      vendor: 'acme',
      model: 'api-v1',
      communication_mode: 'api',
      capability_profile_json: {
        dynamic_qr: { api_direct: true, mqtt: false },
        flows: ['dynamic_qr:api_direct', 'static_payment_notification']
      },
      status: 'active'
    },
    _label: 'POST /admin/devices dynamic-api'
  });
  const dynamicDeviceId = dynamicDevice?.data?.id;
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/bind`, {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      outlet_id: dynamicOutletId,
      terminal_id: dynamicTerminalId
    },
    _label: 'POST /admin/devices/:id/bind dynamic-api'
  });
  await reqExpect('/device/transactions/dynamic-qr', 400, {
    method: 'POST',
    headers: { Authorization: `Bearer ${DEVICE_TOKEN}` },
    body: {
      device_id: deviceId,
      terminal_id: dynamicTerminalId,
      amount: 15000,
      currency: 'IDR',
      request_id: `DYN-STATIC-${ts}`
    },
    _label: 'POST /device/transactions/dynamic-qr unsupported device'
  });
  await reqExpect('/device/heartbeat', 403, {
    method: 'POST',
    headers: {
      'X-Device-Id': deviceId,
      'X-Device-Secret': deviceSecret
    },
    body: {
      device_id: dynamicDeviceId,
      timestamp: new Date().toISOString(),
      network_strength: 80,
      battery_level: 70,
      state: 'wrong-device'
    },
    _label: 'POST /device/heartbeat credential wrong device'
  });
  const dynamicRequestId = `DYN-REQ-${ts}`;
  const dynamicQr = await reqDevice('/device/transactions/dynamic-qr', {
    method: 'POST',
    headers: { 'Idempotency-Key': dynamicRequestId },
    body: {
      device_id: dynamicDeviceId,
      terminal_id: dynamicTerminalId,
      amount: 32100,
      currency: 'IDR',
      request_id: dynamicRequestId
    },
    _label: 'POST /device/transactions/dynamic-qr'
  });
  const dynamicQrReplay = await reqDevice('/device/transactions/dynamic-qr', {
    method: 'POST',
    headers: { 'Idempotency-Key': dynamicRequestId },
    body: {
      device_id: dynamicDeviceId,
      terminal_id: dynamicTerminalId,
      amount: 32100,
      currency: 'IDR',
      request_id: dynamicRequestId
    },
    _label: 'POST /device/transactions/dynamic-qr duplicate'
  });
  if (dynamicQr?.data?.transaction_id !== dynamicQrReplay?.data?.transaction_id) {
    throw new Error('dynamic QR idempotency returned a different transaction');
  }
  const dynamicCallback = {
    partner_reference: dynamicQr?.data?.partner_reference,
    partner_txn_id: `PTX-DYN-${ts}`,
    amount: 32100,
    currency: 'IDR',
    payment_status: 'paid',
    status: 'paid',
    paid_at: new Date().toISOString()
  };
  const dynamicSignature = createHmac('sha256', SECRET).update(JSON.stringify(dynamicCallback)).digest('hex');
  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': dynamicSignature },
    body: { ...dynamicCallback, signature: dynamicSignature },
    _label: 'POST /integrations/qris/callback dynamic-api'
  });
  await reqAdmin(`/admin/transactions/${dynamicQr?.data?.transaction_id}`, {
    _label: 'GET /admin/transactions/:id dynamic-api'
  });
  const dueDynamicTx = await reqAdmin('/admin/transactions', {
    method: 'POST',
    body: {
      partner_reference: `DUE-DYN-${ts}`,
      merchant_id: merchantId,
      outlet_id: dynamicOutletId,
      terminal_id: dynamicTerminalId,
      device_id: dynamicDeviceId,
      amount: 12000,
      currency: 'IDR',
      qr_mode: 'dynamic',
      initiation_mode: 'dynamic_api',
      status: 'awaiting_payment',
      expired_at: new Date(Date.now() - 60_000).toISOString()
    },
    _label: 'POST /admin/transactions due dynamic'
  });
  await reqAdmin('/admin/transactions/expire-due', {
    method: 'POST',
    body: { limit: 10 },
    _label: 'POST /admin/transactions/expire-due'
  });
  await reqAdmin(`/admin/transactions/${dueDynamicTx?.data?.id}`, {
    _label: 'GET /admin/transactions/:id expired dynamic'
  });

  const mqttOutlet = await reqAdmin(`/admin/merchants/${merchantId}/outlets`, {
    method: 'POST',
    body: { name: `Dynamic MQTT Outlet ${ts}` },
    _label: 'POST /admin/merchants/:id/outlets dynamic-mqtt'
  });
  const mqttOutletId = mqttOutlet?.data?.id;
  const mqttTerminal = await reqAdmin(`/admin/outlets/${mqttOutletId}/terminals`, {
    method: 'POST',
    body: { terminal_code: `TERM-MQTT-${ts}`, qr_mode: 'dynamic_mqtt' },
    _label: 'POST /admin/outlets/:id/terminals dynamic-mqtt'
  });
  const mqttTerminalId = mqttTerminal?.data?.id;
  const mqttDevice = await reqAdmin('/admin/devices', {
    method: 'POST',
    body: {
      device_code: `DEV-MQTT-${ts}`,
      vendor: 'acme',
      model: 'mqtt-v1',
      communication_mode: 'mqtt',
      capability_profile_json: {
        dynamic_qr: { api_direct: false, mqtt: true },
        flows: ['dynamic_qr:mqtt', 'static_payment_notification']
      },
      status: 'active'
    },
    _label: 'POST /admin/devices dynamic-mqtt'
  });
  const mqttDeviceId = mqttDevice?.data?.id;
  await reqAdmin(`/admin/devices/${mqttDeviceId}/bind`, {
    method: 'POST',
    body: {
      merchant_id: merchantId,
      outlet_id: mqttOutletId,
      terminal_id: mqttTerminalId
    },
    _label: 'POST /admin/devices/:id/bind dynamic-mqtt'
  });
  const mqttRequestId = `MQTT-DYN-${ts}`;
  const mqttQr = await reqDevice('/device/mqtt/uplink/dynamic-qr/request', {
    method: 'POST',
    body: {
      message_type: 'dynamic_qr_request',
      request_id: mqttRequestId,
      device_id: mqttDeviceId,
      terminal_id: mqttTerminalId,
      amount: 43200,
      currency: 'IDR',
      created_at: new Date().toISOString()
    },
    _label: 'POST /device/mqtt/uplink/dynamic-qr/request'
  });
  const mqttQrReplay = await reqDevice('/device/mqtt/uplink/dynamic-qr/request', {
    method: 'POST',
    body: {
      message_type: 'dynamic_qr_request',
      request_id: mqttRequestId,
      device_id: mqttDeviceId,
      terminal_id: mqttTerminalId,
      amount: 43200,
      currency: 'IDR',
      created_at: new Date().toISOString()
    },
    _label: 'POST /device/mqtt/uplink/dynamic-qr/request duplicate'
  });
  if (mqttQr?.data?.transaction_id !== mqttQrReplay?.data?.transaction_id) {
    throw new Error('MQTT dynamic QR idempotency returned a different transaction');
  }
  await reqAdmin(`/admin/devices/${mqttDeviceId}/mqtt-messages?correlation_id=${mqttRequestId}`, {
    _label: 'GET /admin/devices/:id/mqtt-messages dynamic-mqtt'
  });
  const mqttCallback = {
    partner_reference: mqttQr?.data?.partner_reference,
    partner_txn_id: `PTX-MQTT-${ts}`,
    amount: 43200,
    currency: 'IDR',
    payment_status: 'paid',
    status: 'paid',
    paid_at: new Date().toISOString()
  };
  const mqttSignature = createHmac('sha256', SECRET).update(JSON.stringify(mqttCallback)).digest('hex');
  await req('/integrations/qris/callback', {
    method: 'POST',
    headers: { 'X-Partner-Signature': mqttSignature },
    body: { ...mqttCallback, signature: mqttSignature },
    _label: 'POST /integrations/qris/callback dynamic-mqtt'
  });
  await reqAdmin(`/admin/transactions/${mqttQr?.data?.transaction_id}`, {
    _label: 'GET /admin/transactions/:id dynamic-mqtt'
  });

  const pushedConfig = await reqAdmin(`/admin/devices/${dynamicDeviceId}/config`, {
    method: 'PATCH',
    body: {
      settings: {
        volume: 65,
        language: 'id-ID',
        heartbeat_interval_seconds: 45
      }
    },
    _label: 'PATCH /admin/devices/:id/config'
  });
  const configVersion = pushedConfig?.data?.config?.config_version;
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/config/status`, {
    _label: 'GET /admin/devices/:id/config/status pending'
  });
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/config/retry-push`, {
    method: 'POST',
    body: {},
    _label: 'POST /admin/devices/:id/config/retry-push'
  });
  await reqDevice(`/device/config?device_id=${dynamicDeviceId}`, {
    _label: 'GET /device/config'
  });
  await reqDevice('/device/config/ack', {
    method: 'POST',
    body: {
      device_id: dynamicDeviceId,
      config_version: configVersion,
      status: 'applied',
      result_payload: { applied_at: new Date().toISOString() }
    },
    _label: 'POST /device/config/ack'
  });
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/config`, {
    _label: 'GET /admin/devices/:id/config'
  });
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/config/status`, {
    _label: 'GET /admin/devices/:id/config/status applied'
  });
  await reqExpect(`/admin/devices/${dynamicDeviceId}/config/retry-push`, 409, {
    method: 'POST',
    headers: { Authorization: `Bearer ${ADMIN_TOKEN}` },
    body: {},
    _label: 'POST /admin/devices/:id/config/retry-push already applied'
  });
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/mqtt-messages?message_type=config_push`, {
    _label: 'GET /admin/devices/:id/mqtt-messages config'
  });
  await reqAdmin(`/admin/devices/${dynamicDeviceId}/mqtt-messages?message_type=config_ack`, {
    _label: 'GET /admin/devices/:id/mqtt-messages config ack'
  });

  console.log(`Smoke point 4 flow done. tx=${txId} device=${deviceId}`);
})();
