const assert = require('assert')
const http = require('http')
const path = require('path')
const fs = require('fs')

const ipcRenderer = require('electron').ipcRenderer
const remote = require('electron').remote

const ipcMain = remote.ipcMain
const session = remote.session
const BrowserWindow = remote.BrowserWindow

describe('session module', function () {
  this.timeout(10000)

  var fixtures = path.resolve(__dirname, 'fixtures')
  var w = null
  var url = 'http://127.0.0.1'

  beforeEach(function () {
    w = new BrowserWindow({
      show: false,
      width: 400,
      height: 400
    })
  })

  afterEach(function () {
    w.destroy()
  })

  describe('session.cookies', function () {
    it('should get cookies', function (done) {
      var server = http.createServer(function (req, res) {
        res.setHeader('Set-Cookie', ['0=0'])
        res.end('finished')
        server.close()
      })
      server.listen(0, '127.0.0.1', function () {
        var port = server.address().port
        w.loadURL(url + ':' + port)
        w.webContents.on('did-finish-load', function () {
          w.webContents.session.cookies.get({
            url: url
          }, function (error, list) {
            var cookie, i, len
            if (error) {
              return done(error)
            }
            for (i = 0, len = list.length; i < len; i++) {
              cookie = list[i]
              if (cookie.name === '0') {
                if (cookie.value === '0') {
                  return done()
                } else {
                  return done('cookie value is ' + cookie.value + ' while expecting 0')
                }
              }
            }
            done('Can not find cookie')
          })
        })
      })
    })

    it('should over-write the existent cookie', function (done) {
      session.defaultSession.cookies.set({
        url: url,
        name: '1',
        value: '1'
      }, function (error) {
        if (error) {
          return done(error)
        }
        session.defaultSession.cookies.get({
          url: url
        }, function (error, list) {
          var cookie, i, len
          if (error) {
            return done(error)
          }
          for (i = 0, len = list.length; i < len; i++) {
            cookie = list[i]
            if (cookie.name === '1') {
              if (cookie.value === '1') {
                return done()
              } else {
                return done('cookie value is ' + cookie.value + ' while expecting 1')
              }
            }
          }
          done('Can not find cookie')
        })
      })
    })

    it('should remove cookies', function (done) {
      session.defaultSession.cookies.set({
        url: url,
        name: '2',
        value: '2'
      }, function (error) {
        if (error) {
          return done(error)
        }
        session.defaultSession.cookies.remove(url, '2', function () {
          session.defaultSession.cookies.get({
            url: url
          }, function (error, list) {
            var cookie, i, len
            if (error) {
              return done(error)
            }
            for (i = 0, len = list.length; i < len; i++) {
              cookie = list[i]
              if (cookie.name === '2') {
                return done('Cookie not deleted')
              }
            }
            done()
          })
        })
      })
    })
  })

  describe('session.clearStorageData(options)', function () {
    fixtures = path.resolve(__dirname, 'fixtures')
    it('clears localstorage data', function (done) {
      ipcMain.on('count', function (event, count) {
        ipcMain.removeAllListeners('count')
        assert(!count)
        done()
      })
      w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html'))
      w.webContents.on('did-finish-load', function () {
        var options = {
          origin: 'file://',
          storages: ['localstorage'],
          quotas: ['persistent']
        }
        w.webContents.session.clearStorageData(options, function () {
          w.webContents.send('getcount')
        })
      })
    })
  })

  describe('session will-download event', function () {
    var w = null

    beforeEach(function () {
      w = new BrowserWindow({
        show: false,
        width: 400,
        height: 400
      })
    })

    afterEach(function () {
      w.destroy()
    })

    it('can cancel default download behavior', function (done) {
      const mockFile = new Buffer(1024)
      const contentDisposition = 'inline; filename="mockFile.txt"'
      const downloadServer = http.createServer(function (req, res) {
        res.writeHead(200, {
          'Content-Length': mockFile.length,
          'Content-Type': 'application/plain',
          'Content-Disposition': contentDisposition
        })
        res.end(mockFile)
        downloadServer.close()
      })

      downloadServer.listen(0, '127.0.0.1', function () {
        const port = downloadServer.address().port
        const url = 'http://127.0.0.1:' + port + '/'

        ipcRenderer.sendSync('set-download-option', false, true)
        w.loadURL(url)
        ipcRenderer.once('download-error', function (event, downloadUrl, filename, error) {
          assert.equal(downloadUrl, url)
          assert.equal(filename, 'mockFile.txt')
          assert.equal(error, 'Object has been destroyed')
          done()
        })
      })
    })
  })

  describe('DownloadItem', function () {
    var mockPDF = new Buffer(1024 * 1024 * 5)
    var contentDisposition = 'inline; filename="mock.pdf"'
    var downloadFilePath = path.join(fixtures, 'mock.pdf')
    var downloadServer = http.createServer(function (req, res) {
      res.writeHead(200, {
        'Content-Length': mockPDF.length,
        'Content-Type': 'application/pdf',
        'Content-Disposition': contentDisposition
      })
      res.end(mockPDF)
      downloadServer.close()
    })
    var assertDownload = function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port) {
      assert.equal(state, 'completed')
      assert.equal(filename, 'mock.pdf')
      assert.equal(url, 'http://127.0.0.1:' + port + '/')
      assert.equal(mimeType, 'application/pdf')
      assert.equal(receivedBytes, mockPDF.length)
      assert.equal(totalBytes, mockPDF.length)
      assert.equal(disposition, contentDisposition)
      assert(fs.existsSync(downloadFilePath))
      fs.unlinkSync(downloadFilePath)
    }

    it('can download using BrowserWindow.loadURL', function (done) {
      downloadServer.listen(0, '127.0.0.1', function () {
        var port = downloadServer.address().port
        ipcRenderer.sendSync('set-download-option', false, false)
        w.loadURL(url + ':' + port)
        ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) {
          assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port)
          done()
        })
      })
    })

    it('can download using WebView.downloadURL', function (done) {
      downloadServer.listen(0, '127.0.0.1', function () {
        var port = downloadServer.address().port
        ipcRenderer.sendSync('set-download-option', false, false)
        var webview = new WebView()
        webview.src = 'file://' + fixtures + '/api/blank.html'
        webview.addEventListener('did-finish-load', function () {
          webview.downloadURL(url + ':' + port + '/')
        })
        ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) {
          assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port)
          document.body.removeChild(webview)
          done()
        })
        document.body.appendChild(webview)
      })
    })

    it('can cancel download', function (done) {
      downloadServer.listen(0, '127.0.0.1', function () {
        var port = downloadServer.address().port
        ipcRenderer.sendSync('set-download-option', true, false)
        w.loadURL(url + ':' + port + '/')
        ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) {
          assert.equal(state, 'cancelled')
          assert.equal(filename, 'mock.pdf')
          assert.equal(mimeType, 'application/pdf')
          assert.equal(receivedBytes, 0)
          assert.equal(totalBytes, mockPDF.length)
          assert.equal(disposition, contentDisposition)
          done()
        })
      })
    })
  })
})