const test = require('tap').test
const sinon = require('sinon')
const fs = require('fs')
const QRCode = require('core/qrcode')
const PngRenderer = require('renderer/png')
const PNG = require('pngjs').PNG
const StreamMock = require('../../mocks/writable-stream')

test('PNG renderer interface', function (t) {
  t.type(PngRenderer.render, 'function',
    'Should have render function')

  t.type(PngRenderer.renderToDataURL, 'function',
    'Should have renderToDataURL function')

  t.type(PngRenderer.renderToFile, 'function',
    'Should have renderToFile function')

  t.type(PngRenderer.renderToFileStream, 'function',
    'Should have renderToFileStream function')

  t.end()
})

test('PNG render', function (t) {
  const sampleQrData = QRCode.create('sample text', { version: 2 })
  let png

  t.notThrow(function () { png = PngRenderer.render(sampleQrData) },
    'Should not throw with only qrData param')

  t.ok(png instanceof PNG,
    'Should return an instance of PNG')

  t.equal(png.width, png.height,
    'Should be a square image')

  // modules: 25, margins: 4 * 2, scale: 4
  t.equal(png.width, (25 + 4 * 2) * 4,
    'Should have correct size')

  t.notThrow(function () {
    png = PngRenderer.render(sampleQrData, {
      margin: 10,
      scale: 1
    })
  }, 'Should not throw with options param')

  t.equal(png.width, png.height,
    'Should be a square image')

  // modules: 25, margins: 10 * 2, scale: 1
  t.equal(png.width, 25 + 10 * 2,
    'Should have correct size')

  t.end()
})

test('PNG renderToDataURL', function (t) {
  const sampleQrData = QRCode.create('sample text', { version: 2 })

  t.plan(6)

  PngRenderer.renderToDataURL(sampleQrData, function (err, url) {
    t.ok(!err,
      'Should not generate errors with only qrData param')

    t.type(url, 'string',
      'Should return a string')
  })

  PngRenderer.renderToDataURL(sampleQrData, { margin: 10, scale: 1 },
    function (err, url) {
      t.ok(!err, 'Should not generate errors with options param')

      t.type(url, 'string',
        'Should return a string')

      t.equal(url.split(',')[0], 'data:image/png;base64',
        'Should have correct header')

      const b64png = url.split(',')[1]
      t.equal(b64png.length % 4, 0,
        'Should have a correct length')
    }
  )
})

test('PNG renderToFile', function (t) {
  const sampleQrData = QRCode.create('sample text', { version: 2 })
  const fileName = 'qrimage.png'
  let fsStub = sinon.stub(fs, 'createWriteStream')
  fsStub.returns(new StreamMock())

  t.plan(6)

  PngRenderer.renderToFile(fileName, sampleQrData, function (err) {
    t.ok(!err,
      'Should not generate errors with only qrData param')

    t.equal(fsStub.getCall(0).args[0], fileName,
      'Should save file with correct file name')
  })

  PngRenderer.renderToFile(fileName, sampleQrData, {
    margin: 10,
    scale: 1
  }, function (err) {
    t.ok(!err,
      'Should not generate errors with options param')

    t.equal(fsStub.getCall(0).args[0], fileName,
      'Should save file with correct file name')
  })

  fsStub.restore()
  fsStub = sinon.stub(fs, 'createWriteStream')
  fsStub.returns(new StreamMock().forceErrorOnWrite())

  PngRenderer.renderToFile(fileName, sampleQrData, function (err) {
    t.ok(err,
      'Should fail if error occurs during save')
  })

  fsStub.restore()
})

test('PNG renderToFileStream', function (t) {
  const sampleQrData = QRCode.create('sample text', { version: 2 })

  t.notThrow(function () {
    PngRenderer.renderToFileStream(new StreamMock(), sampleQrData)
  }, 'Should not throw with only qrData param')

  t.notThrow(function () {
    PngRenderer.renderToFileStream(new StreamMock(), sampleQrData, {
      margin: 10,
      scale: 1
    })
  }, 'Should not throw with options param')

  t.end()
})