const openapi = require('..')
const nock = require('nock')
const { isPlainObject } = require('lodash')

describe('npm module', () => {
  describe('`schemas` property', () => {
    test('object names', () => {
      expect(isPlainObject(openapi.schemas)).toBe(true)
      const schemaNames = Object.keys(openapi.schemas)
      expect(schemaNames).toContain('api.github.com')

      const gheSchemaNames = schemaNames.filter(name => name.startsWith('ghe-'))
      expect(gheSchemaNames.length).toBe(schemaNames.length - 2)

      const dereffedSchemaNames = schemaNames.filter(name => name.endsWith('-deref'))
      expect(dereffedSchemaNames.length).toBe(schemaNames.length / 2)
    })

    test('object values', () => {
      const schemaValues = Object.values(openapi.schemas)
      expect(schemaValues.every(value => isPlainObject(value))).toBe(true)
    })
  })

  describe('getSchema() async function', () => {
    test('is a function', () => {
      expect(typeof openapi.getSchema).toBe('function')
    })

    test('allows a schema to be retrieved by name', async () => {
      const schemaName = Object.keys(openapi.schemas).find(
        name => name.startsWith('ghe-') && name.endsWith('-deref.json')
      )
      expect(schemaName).toBe()
      const schema = await openapi.getSchema(schemaName)
      expect(isPlainObject(schema)).toBe(true)
      expect(isPlainObject(schema.paths)).toBe(true)
    })

    test('allows a schema to be retrieved by remote URL', async () => {
      const schemaName = 'https://openapi.github.com/example.json'
      const mock = nock('https://openapi.github.com')
        .get('/example.json')
        .reply(200, {
          name: 'some remote staging version of the schema'
        })

      const schema = await openapi.getSchema(schemaName)
      expect(mock.isDone()).toBe(true)
      expect(schema.name).toBe('some remote staging version of the schema')
    })

    test('returns api.github.com schema if no arguments are passed', async () => {
      const schema = await openapi.getSchema()
      expect(isPlainObject(schema)).toBe(true)
      expect(isPlainObject(schema.paths)).toBe(true)
    })

    test('throws an error if a nonexistent schema name is provided', async () => {
      let message = false
      try {
        await openapi.getSchema('bad-schema-name')
      } catch (e) {
        message = e.message
      }
      expect(message).toContain('There is no schema named \'bad-schema-name\'.')
    })
  })

  describe('getOperations() async function', () => {
    test('is a function', () => {
      expect(typeof openapi.getOperations).toBe('function')
    })

    test('returns operations from the api.github.com schema when no argument is provided', async () => {
      const operations = await openapi.getOperations()

      expect(Array.isArray(operations)).toBe(true)
      expect(operations.length).toBeGreaterThan(100)
      const invalidOperations = operations.filter(operation => !operation.isValid())
      expect(invalidOperations.length).toBe(0)
    })
  })
})
