const path = require('path'),
      { exec } = require('child_process'),
      { expect } = require('chai'),
      swap = require('../../../src/swap'),

      eID = 'sample-1234',
      packageName = 'sample',
      restart = true;

describe('swap', () => {
  const TESTS_DIR = path.resolve(__dirname, '..', '..'),
        TEST_TEMP_DIR = path.resolve(TESTS_DIR, '.tmp'),
        TEST_ASSETS_DIR = path.resolve(TESTS_DIR, 'assets'),
        SAMPLE_APP_DIR = path.resolve(TEST_ASSETS_DIR, 'sample-application');

  beforeEach((done) => {
    exec(`mkdir -p ${TEST_TEMP_DIR} && cp -R ${SAMPLE_APP_DIR}/* ${TEST_TEMP_DIR}/`, (err) => {
      done(err);
    });
  });

  afterEach((done) => {
    exec(`rm -rf ${TEST_TEMP_DIR}`, () => {
      done();
    });
  });

  it('should throw error if the callback is not provided', () => {
    let error;
    try { swap(); }
    catch (e) { error = e; }
    expect(error).to.be.instanceof(Error);
    expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - callback is a required parameter');
  });

  it('should throw error if the callback is not a function', () => {
    let error;
    try { swap({}, 'invalidCallbackParam'); }
    catch (e) { error = e; }
    expect(error).to.be.instanceof(Error);
    expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - callback should be of type function');
  });

  it('should throw error if the input data is not provided', (done) => {
    swap(null, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData is a required parameter');
      done();
    });
  });

  it('should throw error if the input data is not object', (done) => {
    swap('invalidInputData', (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData should be of type object');
      done();
    });
  });

  it('should throw error if the eID is not provided', (done) => {
    swap({}, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.eID is a required field');
      done();
    });
  });

  it('should throw error if the eID is not string', (done) => {
    swap({ eID: 1234 }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.eID should be of type string');
      done();
    });
  });

  it('should throw error if the packageName is not provided', (done) => {
    swap({ eID }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.packageName is a required field');
      done();
    });
  });

  it('should throw error if the packageName is not string', (done) => {
    swap({ eID, packageName: 1234 }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.packageName should be of type string');
      done();
    });
  });

  it('should throw error if the extractInfo is not provided', (done) => {
    swap({ eID, packageName }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.extractInfo is a required field');
      done();
    });
  });

  it('should throw error if the extractInfo is not object', (done) => {
    swap({ eID, packageName, extractInfo: 'invalid extractInfo' }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.extractInfo should be of type object');
      done();
    });
  });

  it('should throw error if the extractInfo.extractDirectory is not provided', (done) => {
    swap({ eID, packageName, extractInfo: {} }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.extractInfo.extractDirectory is a required field');
      done();
    });
  });

  it('should throw error if the extractInfo.extractDirectory is not string', (done) => {
    swap({ eID, packageName, extractInfo: { extractDirectory: 1 } }, (error) => {
      expect(error).to.be.instanceof(Error);
      expect(error).to.have.property('message', 'InvalidArgumentException: Hermes~swap - swapInputData.extractInfo.extractDirectory should be of type string');
      done();
    });
  });

  it('should run the relauncher', (done) => {
    const relauncherPath = path.resolve(TEST_ASSETS_DIR, 'relaunchers', 'relauncher-shell'),
          options = {
            relauncher: {
              program: relauncherPath,
              args: ['arg1'],
            },
          };
    swap({
      eID,
      packageName,
      extractInfo: { extractDirectory: TEST_TEMP_DIR },
      restart,
    }, (error) => {
      setTimeout(() => {
        expect(error).to.eql(null);
        done();
      }, 1000);
    }, options);
  });

  it('should run the relauncher without arguments', (done) => {
    const relauncherPath = path.resolve(TEST_ASSETS_DIR, 'relaunchers', 'relauncher-shell'),
          options = { relauncher: { program: relauncherPath } };
    swap({
      eID,
      packageName,
      extractInfo: { extractDirectory: TEST_TEMP_DIR },
      restart,
    }, (error) => {
      setTimeout(() => {
        expect(error).to.eql(null);
        done();
      }, 1000);
    }, options);
  });
});
