var http = require('http');
var https = require('https');
var net = require('net');
var fs = require('fs');
var path = require('path');
var should = require('should');
var tunnel = require('../index.js');

function readPem(file) {
  return fs.readFileSync(path.join('test/keys', file + '.pem'));
}

var serverKey = readPem('server1-key');
var serverCert = readPem('server1-cert');
var serverCA = readPem('ca1-cert');
var proxyKey = readPem('proxy1-key');
var proxyCert = readPem('proxy1-cert');
var proxyCA = readPem('ca2-cert');
var client1Key = readPem('client1-key');
var client1Cert = readPem('client1-cert');
var client1CA = readPem('ca3-cert');
var client2Key = readPem('client2-key');
var client2Cert = readPem('client2-cert');
var client2CA = readPem('ca4-cert');

describe('HTTPS over HTTPS', function() {
  it('should finish without error', function(done) {
    var serverPort = 3006;
    var proxyPort = 3007;
    var poolSize = 3;
    var N = 5;
    var serverConnect = 0;
    var proxyConnect = 0;
    var clientConnect = 0;
    var server;
    var proxy;
    var agent;

    server = https.createServer({
      key: serverKey,
      cert: serverCert,
      ca: [client1CA],
      requestCert: true,
      rejectUnauthorized: true
    }, function(req, res) {
      tunnel.debug('SERVER: got request');
      ++serverConnect;
      res.writeHead(200);
      res.end('Hello' + req.url);
      tunnel.debug('SERVER: sending response');
    });
    server.listen(serverPort, setupProxy);

    function setupProxy() {
      proxy = https.createServer({
        key: proxyKey,
        cert: proxyCert,
        ca: [client2CA],
        requestCert: true,
        rejectUnauthorized: true
      }, function(req, res) {
        should.fail();
      });
      proxy.on('upgrade', onConnect); // for v0.6
      proxy.on('connect', onConnect); // for v0.7 or later

      function onConnect(req, clientSocket, head) {
        tunnel.debug('PROXY: got CONNECT request');
        req.method.should.equal('CONNECT');
        req.url.should.equal('localhost:' + serverPort);
        req.headers.should.not.have.property('transfer-encoding');
        ++proxyConnect;

        var serverSocket = net.connect(serverPort, function() {
          tunnel.debug('PROXY: replying to client CONNECT request');
          clientSocket.write('HTTP/1.1 200 Connection established\r\n\r\n');
          clientSocket.pipe(serverSocket);
          serverSocket.write(head);
          serverSocket.pipe(clientSocket);
          // workaround, see joyent/node#2524
          serverSocket.on('end', function() {
            clientSocket.end();
          });
        });
      }
      proxy.listen(proxyPort, setupClient);
    }

    function setupClient() {
      agent = tunnel.httpsOverHttps({
        maxSockets: poolSize,
        // client certification for origin server
        key: client1Key,
        cert: client1Cert,
        ca: [serverCA],
        rejectUnauthroized: true,
        proxy: {
          port: proxyPort,
          // client certification for proxy
          key: client2Key,
          cert: client2Cert,
          ca: [proxyCA],
          rejectUnauthroized: true
        }
      });

      for (var i = 0; i < N; ++i) {
        doClientRequest(i);
      }

      function doClientRequest(i) {
        tunnel.debug('CLIENT: Making HTTPS request (%d)', i);
        var req = https.get({
          port: serverPort,
          path: '/' + i,
          agent: agent
        }, function(res) {
          tunnel.debug('CLIENT: got HTTPS response (%d)', i);
          res.setEncoding('utf8');
          res.on('data', function(data) {
            data.should.equal('Hello/' + i);
          });
          res.on('end', function() {
            ++clientConnect;
            if (clientConnect === N) {
              proxy.close();
              server.close();
            }
          });
        });
      }
    }

    server.on('close', function() {
      serverConnect.should.equal(N);
      proxyConnect.should.equal(poolSize);
      clientConnect.should.equal(N);

      var name = 'localhost:' + serverPort;
      agent.sockets.should.be.empty;
      agent.requests.should.be.empty;
  
      done();
    });
  });
});