const expect = require('expect');
const request = require('supertest');
const {ObjectID} = require('mongodb');

const {app} = require('../server');
const {Todo} = require('../models/todo');
const {User} = require('../models/user');
const {todos, populateTodos, users, populateUsers, userjson, mypwdcrypted, mypwdchiaro, date_login} = require(
    './seed/seed');

const tools = require('../tools/general');

// const { debug } = require('debug');
// const log = debug('server');

let jsonUser1 = {
  email: 'paolo.arena77@gmail.com',
  password: '$2a$12$hTv40mdq.x35Up7HQ9faae1JgHrohcvp45vt8eMkGhQv/Zv.8.MIG',
  username: 'paoloar77',
  name: 'Paolo',
  surname: 'Arena',
  idapp: '1',
  lang: 'it',
  keyappid: 'KKPPAA5KJK435J3KSS9F9D8S9F8SD98F9SDF',
};

beforeEach(async function() {
  this.timeout(5000);
  await populateUsers()
})

beforeEach(async function() {
  this.timeout(5000);
  await populateTodos()
})

const IndexUserToCreate = 2;
const IndexTodoToCreate = 3;

// console.log('UserOne:', users[0]);
// console.log('UserTwo:', users[0]);

// console.log('userjson', userjson);

// const useragent = "auth Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36";
const useragent = 'node-superagent/2.3.0';

const testsingolo = false;



if (testsingolo) {
  describe('POST /users/login', () => {
    it.only('should login user and return auth token', (done) => {
      request(app).post('/users/login')
          // .set('x-auth', users[0].tokens[0].token)
          .send({
            username: users[0].username,
            name: users[0].name,
            surname: users[0].surname,
            password: mypwdchiaro,
            idapp: users[0].idapp,
            keyappid: users[0].keyappid,
            lang: users[0].lang,
            subs: null,
          }).expect(200).expect((res) => {
        expect(res.headers['x-auth']).toBeTruthy();
      }).end((err, res) => {
        if (err) {
          return done(err);
        }

        User.findById(users[0]._id).then((user) => {
          expect(user.tokens[0]).toEqual({
            access: 'auth',
            // token: res.headers['x-auth'],
            date_login: date_login,
          });
          return done();
        }).catch((e) => done(e));
      });
    });
  });

} else {

  describe('POST /users', function() {
    this.timeout(8000);
    it('should create a user', (done) => {
      request(app).
          post('/users').
          send(users[IndexUserToCreate]).
          expect(200).
          expect((res) => {
            expect(res.headers['x-auth']).toBeTruthy();
            expect(res.body._id).toBeTruthy();
            expect(res.body.email).toBe(users[IndexUserToCreate].email);
            expect(res.body.username).toBe(users[IndexUserToCreate].username);
            expect(res.body.name).toBe(users[IndexUserToCreate].name);
            expect(res.body.surname).toBe(users[IndexUserToCreate].surname);
          }).
          end((err) => {

            if (err) {
              console.log('ERR:', err);
              return done(err);
            }

            return User.findOne({email: users[IndexUserToCreate].email}).
                then((user) => {
                  expect(user).toBeTruthy();
                  return done();
                }).
                catch((e) => {
                  return done(e)
                });
          });
    });

    it('should return validation errors if request invalid', (done) => {
      request(app).post('/users').send({
        email: 'test@test.com',
        username: 'and',
        password: '123',
      }).expect(400).end(done);
    });

    it('should not create user if email in use', (done) => {
      request(app).post('/users').send(users[1]).expect(400).end(done);
    });
  });

  describe('GET /users/idapp/myusername', () => {
    it('should return 200 if myusername exist', (done) => {
      request(app).get('/users/' + users[0].idapp + '/' + users[0].username)
          // .set('x-auth', users[0].tokens[0].token)
          .expect(200).end(done);
    });

    it('should return 404 if myusername doesn\'t exist', (done) => {
      request(app).
          get('/users/' + users[0].idapp + '/' + users[0].username + 'pippo').
          expect(404).
          end(done);
    });
  });

  describe('POST /users/login', () => {
    it('should login user and return auth token', (done) => {
      request(app).post('/users/login')
          // .set('x-auth', users[0].tokens[0].token)
          .send({
            username: users[0].username,
            password: mypwdchiaro,
            idapp: users[0].idapp,
            keyappid: users[0].keyappid,
            lang: users[0].lang,
          }).expect(200).expect((res) => {
        expect(res.headers['x-auth']).toBeTruthy();
      }).end((err, res) => {
        if (err) {
          return done(err);
        }

        return User.findById(users[0]._id).then((user) => {
          expect(user.tokens[0]._doc).toEqual({
            _id: user.tokens[0]._id,
            access: 'auth',
            browser: useragent,
            date_login: date_login,
            token: users[0].tokens[0].token,
          });
          return done();
        }).catch((e) => done(e));
      });
    });

    it('should reject invalid login', function(done) {
      this.timeout(6000);
      request(app).post('/users/login').send({
        username: users[0].username,
        password: mypwdchiaro + '1',
      }).expect(400).expect((res) => {
        expect(res.headers['x-auth']).not.toBeTruthy();
      }).end((err, res) => {
        if (err) {
          return done(err);
        }

        return User.findById(users[1]._id).then((user) => {
          expect(user.tokens.length).toBe(1);
          return done();
        }).catch((e) => done(e));
      });
    });

  });

  describe('DELETE /users/me/token', () => {
    it('should logout user deleting auth token', (done) => {
      request(app).
          delete('/users/me/token').
          set('x-auth', users[0].tokens[0].token).
          send().
          expect(200).
          expect((res) => {
            expect(res.headers['x-auth']).not.toBeTruthy();
          }).
          end((err, res) => {
            if (err) {
              return done(err);
            }

            return done();
          });
    });

    it('should return 403 deleting with an invalid token', (done) => {
      request(app).
          delete('/users/me/token').
          set('x-auth', users[0].tokens[0].token + '1').
          send().
          expect(403).
          end((err, res) => {
            if (err) {
              return done(err);
            }

            return done();
          });
    });
  });

  describe('POST /todos', () => {

    it('should create a new Todos', (done) => {
      request(app).
          post('/todos').
          set('x-auth', users[0].tokens[0].token).
          send(todos[IndexTodoToCreate]).
          expect(200).
          end((err, res) => {
            if (err) {
              return done(err);
            }

            return Todo.find({descr: todos[IndexTodoToCreate].descr}).
                then((arr_todos) => {
                  expect(arr_todos.length).toBe(1);
                  expect(arr_todos[0].descr).
                      toBe(todos[IndexTodoToCreate].descr);
                  expect(String(arr_todos[0]._id)).
                      toBe(String(todos[IndexTodoToCreate]._id));
                  expect(String(arr_todos[0].userId)).
                      toBe(String(users[0]._id));
                  done();
                }).
                catch((e) => done(e));
          });
    });

    it('should return 404 if not authenticated', (done) => {
      request(app).
          post('/todos').
          set('x-auth', users[0].tokens[0].token).
          send(todos[IndexTodoToCreate]).
          expect(404).
          end((err) => {
            return done();
          });
    });

    it('should not create todo with invalid body data', (done) => {
      request(app).
          post('/todos').
          set('x-auth', users[0].tokens[0].token).
          send({}).
          expect(400).
          end(done);
    });
  });

  describe('GET /todos', () => {
    it('should get all todos', (done) => {
      request(app).
          get(`/todos/`).
          set('x-auth', users[0].tokens[0].token).
          expect(200).
          expect((res) => {
            expect(res.body.todos.length).toBe(2);
          }).
          end(done);
    });
  });

  describe('GET /todos/:id', () => {
    it('should return todos of the User', (done) => {
      request(app).
          get(`/todos/${todos[0].userId.toString()}`).
          set('x-auth', users[0].tokens[0].token).
          expect(200).
          expect((res) => {
            let miores = res;
            let miadescr = miores.body.todos[0][0].descr;
            expect(res.body.todos.length).toBe(2);
            expect(miadescr).toBe(todos[1].descr);
          }).
          end(done);
    });

    it('should not return todo doc created by other user', (done) => {
      request(app).
          get(`/todos/${todos[1].userId.toString()}`).
          set('x-auth', users[0].tokens[0].token).
          expect(404).
          end(done);
    });

    it('FORBIDDEN ! should return [] if user not found', (done) => {
      var hexId = new ObjectID().toHexString();

      request(app).
          get(`/todos/${hexId}`).
          set('x-auth', users[0].tokens[0].token).
          expect(404).
          expect((res) => {
            console.log('res', res.statustodo);
            expect(res.body.todos).toBe(undefined);
          }).
          end(done);
    });

    it('should return 404 for non-object ids', (done) => {
      request(app).
          get('/todos/123abc').
          set('x-auth', users[0].tokens[0].token).
          expect(404).
          end(done);
    });
  });

  describe('DELETE /todos/:id', () => {
    it('should hide a todo', (done) => {
      var hexId = todos[0]._id.toString();

      request(app).
          delete(`/todos/${hexId}`).
          set('x-auth', users[0].tokens[0].token).
          expect(200).
          expect((res) => {
            expect(res.body.todo._id).toBe(hexId);
          }).
          end((err, res) => {
            if (err) {
              return done(err);
            }

            Todo.findById(hexId).then((todo) => {
              expect(todo.deleted).toBe(true);
              return done();
            }).catch((e) => done(e));
          });
    });

    it('should return 404 if todo not found', (done) => {
      var hexId = new ObjectID().toHexString();

      request(app).
          delete(`/todos/${hexId}`).
          set('x-auth', users[0].tokens[0].token).
          expect(404).
          end(done);
    });

    it('should return 404 if object id is invalid', (done) => {
      request(app).
          delete('/todos/123abc').
          set('x-auth', users[0].tokens[0].token).
          expect(404).
          end(done);
    });
  });

  describe('PATCH /todos/:id', () => {
    it('should update the todo', (done) => {
      var hexId = todos[0]._id.toHexString();
      var descr = 'This should be the new text';

      request(app).
          patch(`/todos/${hexId}`).
          set('x-auth', users[0].tokens[0].token).
          send({
            statustodo: 1,
            descr,
          }).
          expect(200).
          expect((res) => {
            expect(res.body.todo.descr).toBe(descr);
            expect(res.body.todo.statustodo).toBe(1);
            // expect(res.body.todo.completedAt).toBeA('number');
          }).
          end(done);
    });

    /*
    it('should not update the todo created by other user', (done) => {
      var hexId = todos[0]._id.toHexString();
      var descr = 'This should be the new text';

      request(app).
          patch(`/todos/${hexId}`).
          set('x-auth', users[1].tokens[0].token).
          send({
            statustodo: 1,
            descr,
          }).
          expect(404).
          end(done);
    });

     */

    // it('should clear completedAt when todo is not completed', (done) => {
    //   var hexId = todos[1]._id.toHexString();
    //   var text = 'This should be the new text!!';
    //
    //   request(app)
    //     .patch(`/todos/${hexId}`)
    //     .set('x-auth', users[1].tokens[0].token)
    //     .send({
    //       completed: false,
    //       text
    //     })
    //     .expect(200)
    //     .expect((res) => {
    //       expect(res.body.todo.text).toBe(text);
    //       expect(res.body.todo.completed).toBe(false);
    //       expect(res.body.todo.completedAt).toNotExist();
    //     })
    //     .end(done);
    // });
  });

}

/*

});





describe('GET /users/me', () => {
  it('should return user if authenticated', (done) => {
    request(app)
      .get('/users/me')
      .set('x-auth', users[0].tokens[0].token)
      .expect(200)
      .expect((res) => {
        expect(res.body._id).toBe(users[0]._id.toHexString());
        expect(res.body.email).toBe(users[0].email);
      })
      .end(done);
  });

  it('should return 404 if not authenticated', (done) => {
    request(app)
      .get('/users/me')
      .expect(404)
      .expect((res) => {
        expect(res.body).toEqual({});
      })
      .end(done);
  });
});

describe('DELETE /users/me/token', () => {
  it('should remove auth token on logout', (done) => {
    request(app)
      .delete('/users/me/token')
      .set('x-auth', users[0].tokens[0].token)
      .expect(200)
      .end((err, res) => {
        if (err) {
          return done(err);
        }

        User.findById(users[0]._id).then((user) => {
          expect(user.tokens.length).toBe(0);
          done();
        }).catch((e) => done(e));
      });
  });
});


// sendemail.sendEmail_Registration("en", "paolo.arena77@gmail.com", "paoloar77", 1, "http://provalink.com");


*/

/*
describe('slow test', function() {

  // Tests will be considered slow after 1 second elapses
  this.slow(1000);

  // Completes after the specified 1 second elapses
  it('should be complete in a second', function(done) {
    setTimeout(done, 1500);
  })

  // Completes immediately
  it('should be complete instantly', function() {})

})
*/
