import request from 'supertest'
import { createApp } from '../src/createApp.js'
import { createMockServer, generateSimpleViteManifest, getRandomPort, mockConfig } from './util.js'
import { expect } from 'chai'

const port = getRandomPort()
const port2 = getRandomPort()

describe('UI Middleware', function () {
  let app
  let mockserver, mockserver2
  let restoreConfig

  before(function () {
    ;({ restore: restoreConfig } = mockConfig({ urls: [`http://localhost:${port}/`] }))
    app = createApp()
  })

  after(function () {
    restoreConfig()
  })

  beforeEach(async function () {
    mockserver = await createMockServer({ port })
    mockserver.respondWith({
      '/manifest.json': generateSimpleViteManifest({ 'example.js': 'test' }),
      '/example.js': ''
    })
  })

  afterEach(async function () {
    await mockserver?.close()
    await mockserver2?.close()
    process.env.CACHE_TTL = 30000
  })

  // Some say, this is not necessary to test
  // But failing startups due to code errors in the probes will cause this to not work
  // Therefore, we should keep this
  it('is healthy', async function () {
    const response = await request(app).get('/healthy')
    expect(response.statusCode).to.equal(200)
  })

  it('fetches manifest data', async function () {
    const response = await request(app).get('/manifests')
    expect(response.statusCode).to.equal(200)
    expect(response.body).to.deep.equal([{ namespace: 'test', path: 'example' }])
  })

  it('caches manifest data', async function () {
    const response = await request(app).get('/manifests')
    expect(response.statusCode).to.equal(200)
    expect(response.body).to.deep.equal([{ namespace: 'test', path: 'example' }])

    mockserver.close()
    mockserver = await createMockServer({ port })
    mockserver.respondWith({
      '/manifest.json': generateSimpleViteManifest({ 'example.js': 'other' }),
      '/example.js': ''
    })

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

    const response2 = await request(app).get('/manifests')
    expect(response2.statusCode).to.equal(200)
    expect(response2.body).to.deep.equal([{ namespace: 'test', path: 'example' }])
  })

  it('refreshes manifest data after caching timeout', async function () {
    process.env.CACHE_TTL = 1
    app = createApp()

    const response = await request(app).get('/manifests')
    expect(response.statusCode).to.equal(200)
    expect(response.body).to.deep.equal([{ namespace: 'test', path: 'example' }])

    mockserver.close()
    mockserver = await createMockServer({ port })
    mockserver.respondWith({
      '/manifest.json': generateSimpleViteManifest({ 'example.js': 'other' }),
      '/example.js': ''
    })

    // wait some time
    await new Promise(resolve => setTimeout(resolve, 10))

    const response2 = await request(app).get('/manifests')
    expect(response2.statusCode).to.equal(200)
    expect(response2.body).to.deep.equal([{ namespace: 'other', path: 'example' }])
  })

  it('can load multiple configurations', async function () {
    ;({ restore: restoreConfig } = mockConfig({ urls: [`http://localhost:${port}/`, `http://localhost:${port2}`] }))

    mockserver.close()
    mockserver = await createMockServer({ port })
    mockserver.respondWith({
      '/manifest.json': generateSimpleViteManifest({ 'example1.js': 'other' }),
      '/example1.js': ''
    })
    mockserver2 = await createMockServer({ port: port2 })
    mockserver2.respondWith({
      '/manifest.json': generateSimpleViteManifest({ 'example2.js': 'thing' }),
      '/example2.js': ''
    })

    process.env.CACHE_TTL = 1
    const app = createApp()

    await request(app)
      .get('/manifests')
      .then(response => {
        expect(response.statusCode).to.equal(200)
        expect(response.body).to.deep.equal([
          { namespace: 'other', path: 'example1' },
          { namespace: 'thing', path: 'example2' }
        ])
      })
  })
})