#!/usr/bin/env node
/*
 Integration smoke tests for DB4js_all.php
 - Uses HTTPS POST JSON to remote API (or custom API_URL)
 - No external deps (Node core only)

 Env:
  - API_URL (default: https://sternwarte-welzheim.de/DB4js_all.php)
  - API_USER / API_PASS (optional Basic Auth)
*/

const https = require('https');
const http = require('http');
const { URL } = require('url');

const API_URL = process.env.API_URL || 'https://sternwarte-welzheim.de/DB4js_all.php';
const API_USER = process.env.API_USER || '';
const API_PASS = process.env.API_PASS || '';

function postJSON(urlStr, bodyObj) {
  return new Promise((resolve, reject) => {
    const url = new URL(urlStr);
    const body = JSON.stringify(bodyObj || {});
    const isHttps = url.protocol === 'https:';
    const lib = isHttps ? https : http;
    const headers = {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(body)
    };
    if (API_USER && API_PASS) {
      const token = Buffer.from(`${API_USER}:${API_PASS}`).toString('base64');
      headers['Authorization'] = `Basic ${token}`;
    }

    const req = lib.request({
      method: 'POST',
      hostname: url.hostname,
      port: url.port || (isHttps ? 443 : 80),
      path: url.pathname + url.search,
      headers,
      rejectUnauthorized: false, // allow self-signed (if any)
      timeout: 15000,
    }, (res) => {
      let data = '';
      res.setEncoding('utf8');
      res.on('data', c => data += c);
      res.on('end', () => {
        let json = null;
        try { json = JSON.parse(data); } catch (e) {}
        if (res.statusCode >= 400) {
          return reject(new Error(`HTTP ${res.statusCode}: ${data}`));
        }
        if (!json) return reject(new Error(`Non-JSON response: ${data}`));
        resolve(json);
      });
    });
    req.on('error', reject);
    req.on('timeout', () => { req.destroy(new Error('Request timeout')); });
    req.write(body);
    req.end();
  });
}

function assert(cond, msg) {
  if (!cond) throw new Error(msg);
}

(async () => {
  const failures = [];
  let step = 0;
  function record(name, fn) {
    return Promise.resolve()
      .then(fn)
      .then(() => console.log(`✔ ${++step}. ${name}`))
      .catch((err) => { failures.push({ name, err }); console.error(`✖ ${++step}. ${name} ->`, err.message); });
  }

  console.log(`API_URL=${API_URL}`);

  await record('PING returns pong + timestamp', async () => {
    const r = await postJSON(API_URL, { cmd: 'PING' });
    assert(r && r.pong === true, 'pong !== true');
    assert(typeof r.timestamp === 'string' && r.timestamp.length > 0, 'timestamp missing');
  });

  await record('LIST_COMMANDS returns command map', async () => {
    const r = await postJSON(API_URL, { cmd: 'LIST_COMMANDS' });
    assert(r && r.commands && typeof r.count === 'number', 'invalid LIST_COMMANDS payload');
  });

  await record('GET_BEOS with alias email works', async () => {
    const r = await postJSON(API_URL, { cmd: 'GET_BEOS', onlyguides: true, what: 'id,name,email' });
    assert(Array.isArray(r), 'GET_BEOS did not return array');
    if (r.length > 0) {
      const it = r[0];
      assert('id' in it, 'beo item missing id');
      assert('name' in it, 'beo item missing name');
      assert(('email' in it) || ('email_1' in it), 'beo item missing email/email_1');
    }
  });

  await record('GET_BEOS with non-existing field falls back', async () => {
    const r = await postJSON(API_URL, { cmd: 'GET_BEOS', onlyguides: 'true', what: 'id,name,doesnotexist' });
    assert(Array.isArray(r), 'GET_BEOS did not return array on fallback');
  });

  let sampleDate = null;
  await record('GET_TERMINE returns array', async () => {
    const r = await postJSON(API_URL, { cmd: 'GET_TERMINE' });
    assert(Array.isArray(r), 'GET_TERMINE did not return array');
    if (r.length > 0) {
      // pick first with possible datum field
      const d = r.find(x => typeof x.datum === 'string');
      if (d) sampleDate = d.datum;
    }
  });

  if (sampleDate) {
    await record('GET_TIME for sample date', async () => {
      const r = await postJSON(API_URL, { cmd: 'GET_TIME', date: sampleDate });
      assert(r && typeof r.time === 'string', 'GET_TIME missing time');
    });

    let sampleFid = null;
    await record('GET_FID for sample date', async () => {
      const r = await postJSON(API_URL, { cmd: 'GET_FID', datum: sampleDate });
      assert(r && ('fid' in r), 'GET_FID missing fid');
      sampleFid = r.fid;
    });

    await record('GET_COUNTS_DATE for sample date', async () => {
      const r = await postJSON(API_URL, { cmd: 'GET_COUNTS_DATE', date: sampleDate });
      assert(r && typeof r.count === 'number', 'GET_COUNTS_DATE invalid');
    });

    if (sampleFid) {
      await record('GET_COUNTS for sample fid', async () => {
        const r = await postJSON(API_URL, { cmd: 'GET_COUNTS', fid: sampleFid });
        assert(r && typeof r.count === 'number', 'GET_COUNTS invalid');
      });
    }
  }

  if (failures.length) {
    console.error(`\n${failures.length} test(s) failed:`);
    failures.forEach((f, i) => console.error(` ${i + 1}) ${f.name}: ${f.err && f.err.stack || f.err}`));
    process.exit(1);
  } else {
    console.log('\nAll integration tests passed.');
  }
})().catch((e) => { console.error('Fatal error:', e); process.exit(1); });
