// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

'use strict'

const helpers = require('./')
const Client = require('../../lib/nano')
const test = require('tape')

helpers.unit = function (method, error) {
  const unitName = 'nano/tests/unit/' + method.join('/')
  const debug = require('debug')(unitName)

  function log (data) {
    debug({ got: data.body })
  }

  let cli = helpers.mockClientOk(log, error)

  //
  // allow database creation and other server stuff
  //
  if (method[1].match(/follow/)) {
    if (method[0] === 'database') {
      cli.server = helpers.mockClientFollow(log, error)
    } else {
      cli = helpers.mockClientFollow(log, error)
    }
  } else {
    cli.server = helpers.mockClientDb(log, error)
  }

  let testNr = 1

  return function () {
    const args = Array.prototype.slice.call(arguments)
    const stub = args.pop()

    test(unitName + ':' + testNr++,
      function (assert) {
        let f
        assert.ok(typeof stub, 'object')

        //
        // document functions and database functions
        // are at the top level in nano
        //
        if (method[0] === 'database') {
        //
        // Due to the way this harness is designed we cannot differentiate between different methods
        // when those methods are embedded on an object.
        // We have two options, either we hardcode the resolution or we write a full harness that
        // can differentiate between methods embedded on an object.
        // I go the hardcoded route for now.
        //
          if (method[1] === 'replicator') {
            f = cli.server.db.replication.enable
          } else {
            f = cli.server.db[method[1]]
          }
        } else if (method[0] === 'view' && method[1] === 'compact') {
          f = cli.view.compact
        } else if (!~['multipart', 'attachment'].indexOf(method[0])) {
          f = cli[method[1]]
        } else {
          f = cli[method[0]][method[1]]
        }
        assert.ok(typeof f, 'function')

        args.push(function (err, req, response) {
          if (error) {
            assert.ok(err)
            return assert.end()
          }

          assert.equal(response.statusCode, 200)
          if (stub.uri) {
            stub.uri = helpers.couch + stub.uri
          } else {
            stub.db = helpers.couch + stub.db
          }

          if (method[1] === 'follow' || method[1] === 'followUpdates') {
            assert.ok(typeof req.httpAgent, 'object')
            delete req.httpAgent // ignore 'httpAgent' in deep equal assert
          }

          // ignore qsStringifyOptions in object comparison
          delete req.qsStringifyOptions

          assert.deepEqual(req, stub)
          assert.end()
        })
        f.apply(null, args)
      })
  }
}

function mockClient (code, path, extra) {
  return function (debug, error) {
    extra = extra || {}
    const opts = Object.assign(extra, {
      url: helpers.couch + path,
      log: debug,
      request: function (req, cb) {
        if (error) {
          return cb(error)
        }
        if (code === 500) {
          cb(new Error('omg connection failed'))
        } else {
          cb(null, {
            statusCode: code,
            headers: {}
          }, req)
        }
      }
    })

    return Client(opts)
  }
}

function mockClientUnparsedError () {
  return function (debug, body) {
    return Client({
      url: helpers.couch,
      log: debug,
      request: function (_, cb) {
        return cb(null, { statusCode: 500 }, body || '<b> Error happened </b>')
      }
    })
  }
}

function mockClientFollow () {
  return function (debug, error) {
    return Client({
      url: helpers.couch,
      log: debug,
      follow: function (qs, cb) {
        if (error) {
          return cb(error)
        }

        return cb(null, qs, { statusCode: 200 })
      }
    })
  }
}

helpers.mockClientFollow = mockClientFollow()
helpers.mockClientUnparsedError = mockClientUnparsedError()
helpers.mockClientDb = mockClient(200, '')
helpers.mockClientOk = mockClient(200, '/mock')
helpers.mockClientFail = mockClient(500, '')
helpers.mockClientJar = mockClient(300, '', { jar: 'is set' })
module.exports = helpers
