// Node 24+: node server.ts saved-intent.json new-response-directory
// Local browser -> your backend -> Quest. Loopback demonstration of one saved intent.
// A hosted application must supply its own authenticated user, tenancy and durable operation store.
import { createServer } from 'node:http';
import { readFile, mkdir, open } from 'node:fs/promises';
import { join } from 'node:path';
import { randomBytes, randomUUID } from 'node:crypto';
import { execute, requestOptions, UPLOAD_BYTES } from './quest.ts';
const [input, directory] = process.argv.slice(2);
if (!input || !directory) throw new Error('node server.ts saved-intent.json new-response-directory');
const bytes = await readFile(input);
if (bytes.length > UPLOAD_BYTES + 4096) throw new Error('Saved intent too large');
const intent = JSON.parse(bytes.toString('utf8')), key = process.env.FOREVERLEARNING_API_KEY ?? '';
requestOptions(intent, key); await mkdir(directory, { mode: 0o700 });
const token = randomBytes(32).toString('hex'), host = '127.0.0.1:4317', origin = 'http://' + host;
let busy = false;
const server = createServer(async (request, response) => {
  response.setHeader('Cache-Control', 'no-store'); response.setHeader('X-Content-Type-Options', 'nosniff');
  response.setHeader('Content-Security-Policy', "default-src 'none'; script-src 'nonce-" + token + "'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'");
  if (request.headers.host !== host) { response.writeHead(403).end(); return; }
  if (request.method === 'GET' && request.url === '/') {
    response.setHeader('Content-Type', 'text/html; charset=utf-8');
    response.end(`<!doctype html><html lang="en"><meta charset="utf-8"><title>Quest backend example</title><h1>Run the saved Quest request</h1><p>This uses the operation already saved on your server. A repeat uses the same identity and body.</p><button id="run">Send saved request</button><pre id="result" role="status"></pre><script nonce="${token}">const button=document.querySelector('#run'),out=document.querySelector('#result');button.onclick=async()=>{button.disabled=true;out.textContent='Waiting for confirmed completion…';try{const reply=await fetch('/run',{method:'POST',headers:{'X-Local-Request':'${token}'}});out.textContent=await reply.text();}catch{out.textContent='Connection interrupted. Check the same saved request.';}finally{button.disabled=false;}};</script></html>`); return;
  }
  if (request.method !== 'POST' || request.url !== '/run' || request.headers.origin !== origin || request.headers['x-local-request'] !== token
    || request.headers['transfer-encoding'] || Number(request.headers['content-length'] ?? 0) !== 0) { response.writeHead(403).end(); return; }
  if (busy) { response.writeHead(409).end('The original operation is still running.'); return; }
  busy = true;
  try {
    const file = await open(join(directory, randomUUID() + '.json'), 'wx', 0o600);
    try { const result = await execute(intent, key); if ('bytes' in result) throw new Error('Use the CLI for binary downloads');
      await file.writeFile(JSON.stringify(result, null, 2) + '\n'); await file.sync();
      response.setHeader('Content-Type', 'application/json'); response.end(JSON.stringify(result.data));
    } finally { await file.close(); }
  } catch { response.writeHead(502).end('Request not confirmed. Recover the same saved request before creating another operation.'); }
  finally { busy = false; }
});
server.listen(4317, '127.0.0.1', () => console.log('Open ' + origin + '. The server holds the key and saved operation.'));
