// Flags: --expose-internals
'use strict';

const common = require('../common');
if (!common.hasCrypto) common.skip('missing crypto');

const h2 = require('http2');
const net = require('net');

async function requestAndClose(server) {
  const client = new net.Socket();

  const address = server.address();
  if (!common.hasIPv6 && address.family === 'IPv6') {
    // Necessary to pass CI running inside containers.
    client.connect(address.port);
  } else {
    client.connect(address);
  }

  client.on('connect', common.mustCall(function() {
    // Send HTTP/2 Preface
    client.write(Buffer.from('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n', 'utf8'));

    // Send a SETTINGS frame (empty payload)
    client.write(Buffer.from([0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00]));

    const streamId = 1;
    // Send a valid HEADERS frame
    const headersFrame = Buffer.concat([
      Buffer.from([
        0x00, 0x00, 0x0e, // Length: 14 bytes
        0x01, // Type: HEADERS
        0x04, // Flags: END_HEADERS
        (streamId >> 24) & 0xFF, // Stream ID: high byte
        (streamId >> 16) & 0xFF,
        (streamId >> 8) & 0xFF,
        streamId & 0xFF, // Stream ID: low byte
      ]),
      Buffer.from([
        0x82, // Indexed Header Field Representation (Predefined ":method: GET")
        0x84, // Indexed Header Field Representation (Predefined ":path: /")
        0x86, // Indexed Header Field Representation (Predefined ":scheme: http")
        0x41, 0x09, // ":authority: localhost" Length: 9 bytes
        0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
      ]),
    ]);
    client.write(headersFrame);

    // Send a valid DATA frame
    const dataFrame = Buffer.concat([
      Buffer.from([
        0x00, 0x00, 0x05, // Length: 5 bytes
        0x00, // Type: DATA
        0x00, // Flags: No flags
        (streamId >> 24) & 0xFF, // Stream ID: high byte
        (streamId >> 16) & 0xFF,
        (streamId >> 8) & 0xFF,
        streamId & 0xFF, // Stream ID: low byte
      ]),
      Buffer.from('Hello', 'utf8'), // Data payload
    ]);
    client.write(dataFrame);

    // Does not wait for server to reply. Shutdown the socket
    client.end();
  }));
}

const server = h2.createServer();

server.on('error', common.mustNotCall());

server.on(
  'session',
  common.mustCall((session) => {
    session.on('close', common.mustCall(() => {
      server.close();
    }));
  }),
);

server.listen(
  0,
  common.mustCall(async () => {
    await requestAndClose(server);
  }),
);
