import http from 'node:http';
import { once } from 'node:events';
import { setTimeout as sleep } from 'node:timers/promises';
import { createHash } from 'node:crypto';
export const FILE = Buffer.alloc(256 * 1024, 'Undici-demo-');
export const FILE_SHA = createHash('sha256').update(FILE).digest('hex');

// Only local, fictional data. Each scenario owns a fresh instance and shuts it down.
export async function startUpstream(port = 0) {
  const state = { active: 0, maxActive: 0, orders: new Map(), nextId: 1, retries: new Map(), events: [] };
  const server = http.createServer(async (req, res) => {
    const url = new URL(req.url, 'http://fixture.test');
    const json = (code, value, headers = {}) => {
      if (!res.destroyed) { res.writeHead(code, { 'content-type': 'application/json', ...headers }); res.end(JSON.stringify(value)); }
    };
    try {
      if (url.pathname === '/catalog') return json(200, { items: [{ id: 1, name: 'Диагностика', price: 2500 }, { id: 2, name: 'Обслуживание', price: 4900 }] });
      if (url.pathname === '/orders' && req.method === 'POST') {
        let text = ''; for await (const chunk of req) { text += chunk; if (text.length > 4096) return json(413, { error: 'body_too_large' }); }
        let data; try { data = JSON.parse(text); } catch { return json(400, { error: 'invalid_json' }); }
        const key = req.headers['idempotency-key'];
        if (!key || !Number.isInteger(data.amount) || data.amount <= 0) return json(422, { error: 'key_and_positive_integer_amount_required' });
        const old = state.orders.get(key);
        if (old) return old.amount === data.amount ? json(200, old, { 'x-idempotent-replay': 'true' }) : json(409, { error: 'key_payload_conflict' });
        const order = { id: state.nextId++, amount: data.amount }; state.orders.set(key, order); return json(201, order);
      }
      if (url.pathname === '/work') {
        state.active++; state.maxActive = Math.max(state.maxActive, state.active);
        state.events.push({ id: url.searchParams.get('id'), phase: 'start', at: performance.now(), active: state.active });
        await sleep(90); state.active--;
        state.events.push({ id: url.searchParams.get('id'), phase: 'end', at: performance.now(), active: state.active });
        return json(200, { id: url.searchParams.get('id') });
      }
      if (url.pathname === '/slow-headers') { await sleep(1800); return json(200, { late: true }); }
      if (url.pathname === '/slow-body') { res.writeHead(200, { 'content-type': 'text/plain' }); res.write('first'); await sleep(1800); if (!res.destroyed) res.end('last'); return; }
      if (url.pathname === '/file') {
        res.writeHead(200, { 'content-type': 'application/octet-stream', 'content-length': FILE.length });
        for (let offset = 0; offset < FILE.length; offset += 16384) {
          if (res.destroyed) return;
          if (!res.write(FILE.subarray(offset, offset + 16384))) await new Promise(resolve => {
            const done = () => { res.off('drain', done); res.off('close', done); resolve(); };
            res.once('drain', done); res.once('close', done);
          });
          await sleep(8);
        }
        if (!res.destroyed) res.end(); return;
      }
      if (url.pathname === '/invalid-json') { res.writeHead(200, { 'content-type': 'application/json' }); return res.end('{bad'); }
      if (url.pathname === '/empty') { res.writeHead(204); return res.end(); }
      if (url.pathname === '/retry') {
        const kind = url.searchParams.get('kind') || '503'; const n = (state.retries.get(kind) || 0) + 1; state.retries.set(kind, n);
        if (n < 3) return json(Number(kind), { attempt: n, message: 'Учебный временный отказ' }, { 'retry-after': '0' });
        return json(200, { attempt: n, recovered: true });
      }
      return json(404, { error: 'not_found' });
    } catch { if (!res.headersSent) json(500, { error: 'fixture_error' }); else res.destroy(); }
  });
  server.listen(port, '127.0.0.1'); await once(server, 'listening');
  return { origin: `http://127.0.0.1:${server.address().port}`, state, close: () => new Promise(resolve => { server.close(resolve); server.closeAllConnections(); }) };
}
