import * as td from 'testdouble'
import { register } from 'prom-client'
import request from 'supertest'
import RedisMock from 'ioredis-mock'

export function generateSimpleViteManifest (mapping) {
  const viteManifest = {}
  for (const [file, value] of Object.entries(mapping)) {
    viteManifest[file] = {
      file,
      meta: typeof value === 'string' ? { manifests: [{ namespace: value }] } : {}
    }
    if (typeof value === 'object') Object.assign(viteManifest[file], value)
  }
  return viteManifest
}

export function mockConfig (obj = {}) {
  td.replaceEsm('fs/promises', {}, {
    readFile () {
      return `baseUrls:\n${obj.urls.map(u => `  - ${u}`).join('\n')}`
    }
  })
}

export function mockFetch (servers = {}) {
  td.replace(global, 'fetch', async function ({ origin, pathname }) {
    const response = servers[origin]?.[pathname]
    if (response === undefined) return new Response('', { status: 404 })
    if (response instanceof Function) return response.apply(this, arguments)

    if (typeof response === 'object') {
      return new Response(JSON.stringify(response), {
        status: 200,
        headers: {
          'Content-Type': 'application/json'
        }
      })
    }
    return new Response(response, { status: 200 })
  })
}

export function mockRedis (data = {}, isEnabled = true) {
  const mock = {
    isReady () { return Promise.resolve() },
    isEnabled () { return isEnabled },
    client: new RedisMock(data),
    pubClient: new RedisMock(),
    subClient: new RedisMock()
  }
  td.replaceEsm('../src/redis.js', mock)
  return mock
}

export async function mockApp () {
  register.clear()
  const { createApp } = await import('../src/create-app.js')
  const app = await createApp()
  app.listen({ port: 0 })
  await request(app.server).get('/ready')
  return app
}