/* eslint-env node, mocha */
'use strict'

const assert = require('assert')
const mock = require('mock-require')
const sinon = require('sinon')

const { createFakeLogger } = require('../testDoubles/loggerFake')
const { removeLibModuleCache, makeMockSocket } = require('./utils')
const realtimeJobStub = require('../testDoubles/realtimeJobStub')

describe('realtime#connection', function () {
  describe('connection', function () {
    let realtime
    let modelStub

    beforeEach(() => {
      removeLibModuleCache()
      modelStub = {
        Note: {
          findOne: sinon.stub()
        },
        User: {},
        Author: {}
      }
      mock('../../lib/logger', createFakeLogger())
      mock('../../lib/history', {})
      mock('../../lib/models', modelStub)
      mock('../../lib/config', {})
      mock('../../lib/realtimeUpdateDirtyNoteJob', realtimeJobStub)
      mock('../../lib/realtimeCleanDanglingUserJob', realtimeJobStub)
      mock('../../lib/realtimeSaveRevisionJob', realtimeJobStub)
      mock('../../lib/ot', require('../testDoubles/otFake'))
      realtime = require('../../lib/realtime')
    })

    afterEach(() => {
      mock.stopAll()
      sinon.restore()
    })

    describe('fail', function () {
      it('should fast return when server not start', () => {
        const mockSocket = makeMockSocket()
        realtime.maintenance = true
        const spy = sinon.spy(realtime, 'parseNoteIdFromSocketAsync')
        realtime.connection(mockSocket)
        assert(!spy.called)
      })

      it('should failed when parse noteId occur error', (done) => {
        const mockSocket = makeMockSocket()
        realtime.maintenance = false
        const parseNoteIdFromSocketSpy = sinon.stub(realtime, 'parseNoteIdFromSocketAsync').callsFake(async (socket) => {
          /* eslint-disable-next-line */
          throw 'error'
        })

        const failConnectionSpy = sinon.stub(realtime, 'failConnection')

        realtime.connection(mockSocket)

        setTimeout(() => {
          assert(parseNoteIdFromSocketSpy.called)
          assert(failConnectionSpy.calledOnce)
          assert.deepStrictEqual(failConnectionSpy.lastCall.args, [500, 'error', mockSocket])
          done()
        }, 50)
      })

      it('should failed when noteId not exists', (done) => {
        const mockSocket = makeMockSocket()
        realtime.maintenance = false
        const parseNoteIdFromSocketSpy = sinon.stub(realtime, 'parseNoteIdFromSocketAsync').callsFake(async (socket) => {
          return null
        })

        const failConnectionSpy = sinon.stub(realtime, 'failConnection')

        realtime.connection(mockSocket)

        setTimeout(() => {
          assert(parseNoteIdFromSocketSpy.called)
          assert(failConnectionSpy.calledOnce)
          assert.deepStrictEqual(failConnectionSpy.lastCall.args, [404, 'note id not found', mockSocket])
          done()
        }, 50)
      })
    })

    it('should success connect', function (done) {
      const mockSocket = makeMockSocket()
      const noteId = 'note123'
      realtime.maintenance = false
      const parseNoteIdFromSocketSpy = sinon.stub(realtime, 'parseNoteIdFromSocketAsync').callsFake(async (socket) => {
        return noteId
      })
      const updateUserDataStub = sinon.stub(realtime, 'updateUserData')

      realtime.connection(mockSocket)

      setTimeout(() => {
        assert.ok(parseNoteIdFromSocketSpy.calledOnce)
        assert(updateUserDataStub.calledOnce)
        done()
      }, 50)
    })

    describe('flow', function () {
      it('should establish connection', function (done) {
        const noteId = 'note123'
        const mockSocket = makeMockSocket(null, {
          noteId: noteId
        })
        mockSocket.request.user.logged_in = true
        mockSocket.request.user.id = 'user1'
        mockSocket.noteId = noteId
        realtime.maintenance = false
        sinon.stub(realtime, 'parseNoteIdFromSocketAsync').callsFake(async (socket) => {
          return noteId
        })
        const updateHistoryStub = sinon.stub(realtime, 'updateHistory')
        const emitOnlineUsersStub = sinon.stub(realtime, 'emitOnlineUsers')
        const emitRefreshStub = sinon.stub(realtime, 'emitRefresh')
        const failConnectionSpy = sinon.spy(realtime, 'failConnection')

        let note = {
          id: noteId,
          authors: [
            {
              userId: 'user1',
              color: 'red',
              user: {
                id: 'user1',
                name: 'Alice'
              }
            },
            {
              userId: 'user2',
              color: 'blue',
              user: {
                id: 'user2',
                name: 'Bob'
              }
            }
          ]
        }
        modelStub.Note.findOne.returns(Promise.resolve(note))
        modelStub.User.getProfile = sinon.stub().callsFake((user) => {
          return user
        })
        sinon.stub(realtime, 'checkViewPermission').returns(true)
        realtime.connection(mockSocket)
        setTimeout(() => {
          assert(modelStub.Note.findOne.calledOnce)
          assert.deepStrictEqual(modelStub.Note.findOne.lastCall.args[0].include, [
            {
              model: modelStub.User,
              as: 'owner'
            }, {
              model: modelStub.User,
              as: 'lastchangeuser'
            }, {
              model: modelStub.Author,
              as: 'authors',
              include: [{
                model: modelStub.User,
                as: 'user'
              }]
            }
          ])
          assert(modelStub.Note.findOne.lastCall.args[0].where.id === noteId)
          assert(updateHistoryStub.calledOnce)
          assert(emitOnlineUsersStub.calledOnce)
          assert(emitRefreshStub.calledOnce)
          assert(failConnectionSpy.callCount === 0)
          assert(realtime.getNotePool()[noteId].id === noteId)
          assert(realtime.getNotePool()[noteId].socks.length === 1)
          assert.deepStrictEqual(realtime.getNotePool()[noteId].authors, {
            user1: {
              userid: 'user1', color: 'red', photo: undefined, name: 'Alice'
            },
            user2: {
              userid: 'user2', color: 'blue', photo: undefined, name: 'Bob'
            }
          })
          assert(Object.keys(realtime.getNotePool()[noteId].users).length === 1)
          done()
        }, 50)
      })
    })
  })
})

@@ -4314,18 +4314,20 @@
         
-le
+cons
 t note =

fix lint on test/realtime/connection.test.js