/**
 * Quick connectivity test for both Duo API integrations.
 * Calls a lightweight read endpoint on each:
 *   Accounts API  → GET /admin/v1/accounts  (lists child accounts)
 *   Admin API     → GET /admin/v1/info/summary  (tenant summary stats)
 *
 * Duo auth: HMAC-SHA1 signed "Authorization: Basic <b64(ikey:sig)>" header
 * https://duo.com/docs/adminapi#authentication
 */

import crypto from 'crypto';
import https from 'https';

// ── credentials from .env.local ──────────────────────────────────────────────
const ACCOUNTS = {
  ikey: process.env.DUOACCOUNTS_INTEGRATION_KEY,
  skey: process.env.DUOACCOUNTS_SECRET_KEY,
  host: process.env.DUOACCOUNTS_API_HOSTNAME,
};
const ADMIN = {
  ikey: process.env.DUOADMIN_INTEGRATION_KEY,
  skey: process.env.DUOADMIN_SECRET_KEY,
  host: process.env.DUOADMIN_API_HOSTNAME,
};

// ── Duo HMAC signer ───────────────────────────────────────────────────────────
function duoSign(ikey, skey, host, method, path, params = {}) {
  const date = new Date().toUTCString();
  const sortedParams = Object.keys(params)
    .sort()
    .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
    .join('&');

  const canon = [date, method.toUpperCase(), host.toLowerCase(), path, sortedParams].join('\n');
  const sig = crypto.createHmac('sha1', skey).update(canon).digest('hex');
  const auth = Buffer.from(`${ikey}:${sig}`).toString('base64');

  return { date, auth: `Basic ${auth}`, query: sortedParams };
}

// ── generic HTTPS GET ─────────────────────────────────────────────────────────
function duoGet(creds, path, params = {}) {
  return new Promise((resolve, reject) => {
    const { date, auth, query } = duoSign(creds.ikey, creds.skey, creds.host, 'GET', path, params);
    const url = `https://${creds.host}${path}${query ? '?' + query : ''}`;

    const req = https.get(url, {
      headers: { Authorization: auth, Date: date, 'Content-Type': 'application/json' },
    }, res => {
      let body = '';
      res.on('data', d => body += d);
      res.on('end', () => {
        try { resolve({ status: res.statusCode, data: JSON.parse(body) }); }
        catch { resolve({ status: res.statusCode, data: body }); }
      });
    });
    req.on('error', reject);
    req.setTimeout(10000, () => { req.destroy(); reject(new Error('Timeout')); });
  });
}

// ── run tests ────────────────────────────────────────────────────────────────
async function main() {
  console.log('=== Duo API Connectivity Test ===\n');

  // Validate env
  for (const [name, val] of Object.entries({ ...ACCOUNTS, ...ADMIN })) {
    if (!val) { console.error(`Missing env var for key: ${name}`); process.exit(1); }
  }

  // 1. Accounts API — POST /accounts/v1/account/list (all Accounts API endpoints use POST)
  console.log('── Accounts API ────────────────────────────────');
  console.log(`Host : ${ACCOUNTS.host}`);
  console.log(`IKey : ${ACCOUNTS.ikey}`);
  try {
    const r = await duoPost(ACCOUNTS, '/accounts/v1/account/list');
    console.log(`HTTP : ${r.status}`);
    if (r.status === 200) {
      const accounts = r.data?.response ?? [];
      console.log(`✓ OK — ${accounts.length} child account(s) returned`);
      accounts.slice(0, 5).forEach(a => console.log(`  · ${a.name} (${a.account_id}) — ${a.api_hostname}`));
    } else {
      console.log(`✗ Response:`, JSON.stringify(r.data, null, 2));
    }
  } catch (e) {
    console.log(`✗ Error: ${e.message}`);
  }

  console.log();

  // 2. Admin API — GET /admin/v1/info/summary
  console.log('── Admin API ───────────────────────────────────');
  console.log(`Host : ${ADMIN.host}`);
  console.log(`IKey : ${ADMIN.ikey}`);
  try {
    const r = await duoGet(ADMIN, '/admin/v1/info/summary');
    console.log(`HTTP : ${r.status}`);
    if (r.status === 200) {
      const s = r.data?.response ?? {};
      console.log('✓ OK — Summary:');
      console.log(`  Users          : ${s.user_count ?? 'n/a'}`);
      console.log(`  Integrations   : ${s.integration_count ?? 'n/a'}`);
      console.log(`  Phones         : ${s.telephony_credits_remaining ?? 'n/a'} credits remaining`);
    } else {
      console.log(`✗ Response:`, JSON.stringify(r.data, null, 2));
    }
  } catch (e) {
    console.log(`✗ Error: ${e.message}`);
  }

  // 3. Admin API — GET /admin/v1/users (first page, limit 5)
  console.log();
  console.log('── Admin API — Users (first 5) ─────────────────');
  try {
    const r = await duoGet(ADMIN, '/admin/v1/users', { limit: '5', offset: '0' });
    console.log(`HTTP : ${r.status}`);
    if (r.status === 200) {
      const users = r.data?.response ?? [];
      console.log(`✓ OK — ${users.length} user(s) in page`);
      users.forEach(u => console.log(`  · ${u.username} — ${u.status} — ${u.email ?? '(no email)'}`));
    } else {
      console.log(`✗ Response:`, JSON.stringify(r.data, null, 2));
    }
  } catch (e) {
    console.log(`✗ Error: ${e.message}`);
  }

  console.log('\n=== Done ===');
}

main();
