'use strict';

const common = require('../common');
const http = require('http');
const assert = require('assert');
const { Writable } = require('stream');
const Countdown = require('../common/countdown');

const N = 2;
let abortRequest = true;

const server = http.Server(common.mustCall((req, res) => {
  const headers = { 'Content-Type': 'text/plain', 'Connection': 'close' };
  headers['Content-Length'] = 50;
  const socket = res.socket;
  res.writeHead(200, headers);
  res.write('aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd');
  if (abortRequest) {
    process.nextTick(() => socket.destroy());
  } else {
    process.nextTick(() => res.end('eeeeeeeeee'));
  }
}, N));

server.listen(0, common.mustCall(() => {
  download();
}));

const finishCountdown = new Countdown(N, common.mustCall(() => {
  server.close();
}));
const reqCountdown = new Countdown(N, common.mustCall());

function download() {
  const opts = {
    port: server.address().port,
    path: '/',
  };
  const req = http.get(opts);
  req.on('error', common.mustNotCall());
  req.on('response', common.mustCall((res) => {
    assert.strictEqual(res.statusCode, 200);
    assert.strictEqual(res.headers.connection, 'close');
    let aborted = false;
    const writable = new Writable({
      write(chunk, encoding, callback) {
        callback();
      }
    });
    res.pipe(writable);
    const _handle = res.socket._handle;
    _handle._close = res.socket._handle.close;
    _handle.close = function(callback) {
      _handle._close();
      // Set readable to true even though request is complete
      if (res.complete) res.readable = true;
      callback();
    };
    if (!abortRequest) {
      res.on('end', common.mustCall(() => {
        reqCountdown.dec();
      }));
      res.on('error', common.mustNotCall());
    } else {
      res.on('aborted', common.mustCall(() => {
        aborted = true;
        reqCountdown.dec();
        writable.end();
      }));
      res.on('error', common.expectsError({
        code: 'ECONNRESET'
      }));
    }

    writable.on('finish', common.mustCall(() => {
      assert.strictEqual(aborted, abortRequest);
      finishCountdown.dec();
      if (finishCountdown.remaining === 0) return;
      abortRequest = false; // Next one should be a good response
      download();
    }));
  }));
  req.end();
}
