const assert = require('assert');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const request = require('supertest');
const fs = require('fs');


const logStub = {};
logStub.info = sinon.stub();
logStub.error = sinon.stub();

const storage = proxyquire('../../server/storage', {
  './log.js': function() {
    return logStub;
  }
});

storage.flushall();

describe('Server integration tests', function() {
  let server;
  let storage;
  let uuid;
  let fileId;

  before(function() {
    const app = proxyquire('../../server/server', {
      './log.js': function() {
        return logStub;
      }
    });

    server = app.server;
    storage = app.storage;
  });

  after(function() {
    storage.flushall();
    storage.quit();
    server.close();
  })

  function upload() {
    return request(server).post('/upload')
                   .field('fname', 'test_upload.txt')
                   .set('X-File-Metadata', JSON.stringify({
                     aad: '11111',
                     id: '111111111111111111111111',
                     filename: 'test_upload.txt'
                   }))
                   .attach('file', './test/test_upload.txt')
  }

  it('Responds with a 200 when the service is up', function() {
    return request(server).get('/').expect(200);
  });

  it('Rejects with a 404 when a file id is not valid', function() {
    return request(server).post('/upload/123')
           .field('fname', 'test_upload.txt')
           .set('X-File-Metadata', JSON.stringify({
               'silly': 'text'
           }))
           .attach('file', './test/test_upload.txt')
           .expect(404)
  })

  it('Accepts a file and stores it when properly uploaded', function(done) {
    upload().then(res => {
                     assert(res.body.hasOwnProperty('delete'));
                     uuid = res.body.delete;
                     assert(res.body.hasOwnProperty('url'));
                     assert(res.body.hasOwnProperty('id'));
                     fileId = res.body.id;
                     fs.access('./static/' + fileId, fs.constants.F_OK, err => {
                       if (err) {
                         done(new Error('The file does not exist'));
                       } else {
                         done();
                       }
                     })
                   })
  })

  it('Responds with a 200 if a file exists', function() {
    return request(server).get('/exists/' + fileId)
                  .expect(200)
  })

  it('Exists in the redis server', function() {
    return storage.exists(fileId)
                  .then(() => assert(1))
                  .catch(err => assert.fail())
  })

  it('Fails delete if the delete token does not match', function() {
    return request(server).post('/delete/' + fileId)
                  .send({ delete_token: 11 })
                  .expect(404);
  })

  it('Fails delete if the id is invalid', function() {
    return request(server).post('/delete/1')
                  .expect(404);
  })

  it('Successfully deletes if the id is valid and the delete token matches', function(done) {
    request(server).post('/delete/' + fileId)
                  .send({ delete_token: uuid })
                  .expect(200)
                  .then(() => {
                    fs.access('./static/' + fileId, fs.constants.F_OK, err => {
                      if (err) {
                        done();
                      } else {
                        done(new Error('The file does not exist'));
                      }
                    })
                  })
  })

  it('Responds with a 404 if a file does not exist', function() {
    return request(server).get('/exists/notfound')
                          .expect(404)
  })

  it('Uploads properly after a delete', function(done) {
    upload().then(res => {
                      assert(res.body.hasOwnProperty('delete'));
                      uuid = res.body.delete;
                      assert(res.body.hasOwnProperty('url'));
                      assert(res.body.hasOwnProperty('id'));
                      fileId = res.body.id;
                      fs.access('./static/' + fileId, fs.constants.F_OK, err => {
                        if (err) {
                          done(new Error('The file does not exist'));
                        } else {
                          done();
                        }
                      })
                    })
  })

  it('Responds with a 200 for the download page', function() {
    return request(server).get('/download/' + fileId)
                          .expect(200);
  })

  it('Downloads a file properly', function() {
    return request(server).get('/assets/download/' + fileId)
                          .then(res => {
                            assert(res.header.hasOwnProperty('content-disposition'));
                            assert(res.header.hasOwnProperty('content-type'))
                            assert(res.header.hasOwnProperty('content-length'))
                            assert(res.header.hasOwnProperty('x-file-metadata'))
                            assert.equal(res.header['content-disposition'], 'attachment; filename=test_upload.txt')
                            assert.equal(res.header['content-type'], 'application/octet-stream')
                          })
  })

  it('The file is deleted after one download', function() {
    assert(!fs.existsSync('./static/' + fileId));
  })

  it('No longer exists in the redis server', function() {
    return storage.exists(fileId)
                  .then(() => assert.fail())
                  .catch(err => assert(1))
  })
});
