import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from '@jest/globals'
import mockfs from 'mock-fs'
import request from 'supertest'
import { createApp } from '../src/createApp'
import { createMockServer, generateSimpleViteManifest, getRandomPort } from './util.js'

describe('File caching service', () => {
  let app
  let mockserver
  const port = getRandomPort()

  beforeAll(() => {
    mockfs({
      './config/manifests': {
        'urls.yaml': `manifests:
          - http://localhost:${port}/manifest.json`
      }
    })
    app = createApp()
  })

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

  beforeEach(async () => {
    mockserver = await createMockServer({ port })
    mockserver.respondWith({
      '/manifest.json': generateSimpleViteManifest({
        'example.js': { imports: ['test.txt'] },
        'test.txt': { },
        'main.css': {},
        'index.html': {
          file: 'index.html.js',
          isEntry: true,
          imports: ['example.js'],
          css: ['main.css']
        }
      }),
      '/example.js': (req, res) => res.setHeader('content-type', 'application/javascript').status(200).send('this is example'),
      '/test.txt': (req, res) => res.setHeader('content-type', 'text/plain').status(200).send('this is test'),
      '/index.html.js': (req, res) => res.setHeader('content-type', 'application/javascript').status(200).send('this is index.html.js'),
      '/index.html': (req, res) => res.setHeader('content-type', 'text/html').status(200).send('<html><head></head><body>it\'s me</body></html>'),
      '/main.css': (req, res) => res.setHeader('content-type', 'text/css').status(200).send('.foo { color: #000; }'),
      '/favicon.ico': 'not really a favicon, though'

    })
    await request(app).get('/ready')
  })

  afterEach(() => {
    mockserver.close()
    process.env.CACHE_TTL = 30000
  })

  it('serves files defined in manifest.json file', async () => {
    const response = await request(app).get('/example.js')
    expect(response.statusCode).toBe(200)
    expect(response.headers['content-type']).toBe('application/javascript; charset=utf-8')
    expect(response.text).toBe('this is example')
    // expect(response.headers['content-security-policy']).toContain('sha256-NzZhMTE2Njc2YTgyNTZmZTdlZGVjZDU3YTNmYzRjNmM1OWZkMTI2NjRkYzZmMWM3YTkwMGU3ZTdhNDlhZmVlMwo=')
    const response2 = await request(app).get('/test.txt')
    expect(response2.statusCode).toBe(200)
    expect(response2.headers['content-type']).toBe('text/plain; charset=utf-8')
    expect(response2.text).toBe('this is test')
  })

  it('serves css files', async () => {
    const response = await request(app).get('/main.css')
    expect(response.statusCode).toBe(200)
    expect(response.headers['content-type']).toBe('text/css; charset=utf-8')
    // expect(response.headers['content-security-policy']).toContain('sha256-YjRiYWRlYTVhYmM5ZTZkNjE2ZGM4YjcwZWRlNzUxMmU0YjgxY2UxMWExOTI2ZjM1NzM1M2Y2MWJjNmUwMmZjMwo=')
  })

  it('serves / as index.html', async () => {
    const response = await request(app).get('/')
    expect(response.statusCode).toBe(200)
    expect(response.headers['content-type']).toBe('text/html; charset=utf-8')
    expect(response.text).toBe('<html><head></head><body>it\'s me</body></html>')
  })

  it('directly fetches files not referenced in manifest.json files from the upstream servers', async () => {
    const response = await request(app).get('/favicon.ico')
    expect(response.statusCode).toBe(200)
    expect(response.body).toBe('not really a favicon, though')
  })

  it('returns 404 if file can not be resolved', async () => {
    const response = await request(app).get('/unknown-file.txt')
    expect(response.statusCode).toBe(404)
  })
})