const crypto = require('crypto');

function stableValue(value) {
  if (Array.isArray(value)) return value.map(stableValue);
  if (value && typeof value === 'object') {
    return Object.keys(value).sort().reduce((out, key) => {
      out[key] = stableValue(value[key]);
      return out;
    }, {});
  }
  return value;
}

function buildNonce(serviceName) {
  return `${String(serviceName || 'SERVICE').toUpperCase()}:${Date.now()}:${crypto.randomBytes(8).toString('hex')}`;
}

function signRequestPayload(serviceName, body, secret, { timestamp, nonce, method = 'POST', path = '' } = {}) {
  const payload = JSON.stringify(stableValue({
    serviceName,
    timestamp: String(timestamp || ''),
    nonce: String(nonce || ''),
    method: String(method || '').toUpperCase(),
    path: String(path || ''),
    body
  }));

  return crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
}

function buildRewardAuthHeaders({ serviceName, secret, body, method = 'POST', path = '' } = {}) {
  if (!serviceName) throw new Error('serviceName is required.');
  if (!secret) throw new Error('secret is required.');

  const timestamp = String(Date.now());
  const nonce = buildNonce(serviceName);
  const signature = signRequestPayload(serviceName, body || {}, secret, {
    timestamp,
    nonce,
    method,
    path
  });

  return {
    'Content-Type': 'application/json',
    'X-AISFOR-SERVICE': String(serviceName).toUpperCase(),
    'X-AISFOR-TIMESTAMP': timestamp,
    'X-AISFOR-NONCE': nonce,
    'X-AISFOR-SIGNATURE': signature
  };
}

async function postRewardPayload({ baseUrl, serviceName, secret, payload, dryRun = true } = {}) {
  if (!baseUrl) throw new Error('baseUrl is required.');
  const path = dryRun ? '/api/reward/dry-run' : '/api/reward';
  const url = new URL(path, baseUrl);
  const headers = buildRewardAuthHeaders({
    serviceName,
    secret,
    body: payload || {},
    method: 'POST',
    path
  });

  const response = await fetch(url, {
    method: 'POST',
    headers,
    body: JSON.stringify(payload || {})
  });
  const body = await response.json();

  return {
    ok: response.ok && Boolean(body.ok),
    status: response.status,
    url: url.toString(),
    dryRun,
    body
  };
}

module.exports = {
  buildRewardAuthHeaders,
  postRewardPayload,
  signRequestPayload,
  stableValue
};
