const { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } = require('@jest/globals')
const mock = require('mock-fs')
const fetchMock = require('node-fetch')
const request = require('supertest')
const createApp = require('../src/createApp')

jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox())

describe('Manifest service', () => {
  let app

  beforeAll(() => {
    mock({
      './config/manifests': {
        'urls.yaml': `manifests:
          - https://some-fake-url.k3s.de/api/manifest.json`
      }
    })
    app = createApp()
  })

  afterAll(() => {
    mock.restore()
  })

  beforeEach(() => {
    fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"thing"}'))
  })

  afterEach(() => {
    fetchMock.restore()
    app.timeout = 30000
  })

  it('is healthy', async () => {
    return await request(app)
      .get('/healthy')
      .then(response => {
        expect(response.statusCode).toBe(200)
      })
  })

  it('fetches manifest data', async () => {
    return await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
      })
  })

  it('caches manifest data', async () => {
    await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
      })

    fetchMock.restore()
    fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"different"}'))

    await new Promise((resolve, reject) => setTimeout(resolve, 150))

    await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
      })
  })

  it('refreshes manifest data after caching timeout', async () => {
    app.timeout = 100

    await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
      })

    fetchMock.restore()
    fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"different"}'))

    await new Promise((resolve, reject) => setTimeout(resolve, 150))

    await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"different"}')])
      })
  })

  it.skip('can load multiple configurations', async () => {
    mock({
      './config/manifests': {
        'urls.yaml': `manifests:
          - https://some-fake-url.k3s.de/api/manifest.json
          - https://some-other-fake-url.k3s.de/api/manifest.json`
      }
    })

    fetchMock.get('https://some-other-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"other"}'))

    const app = createApp()

    await request(app)
      .get('/api/manifest.json')
      .then(response => {
        expect(response.statusCode).toBe(200)
        expect(response.body).toEqual([JSON.parse('{"some":"thing"}'), JSON.parse('{"some":"other"}')])
      })
  })
})