import fetch from 'node-fetch'
import { config } from './config.js'
import { getRedisKey, viteManifestToDeps, viteToOxManifest } from './util.js'
import { logger } from './logger.js'
import * as cache from './cache.js'

export async function fetchViteManifests () {
  // vite manifests contains a set of objects with the vite-manifests
  // from the corresponding registered services
  const viteManifests = await Promise.all(config.urls.map(async baseUrl => {
    // fetch the manifests
    const result = await fetch(new URL('manifest.json', baseUrl))
    if (!result.ok) throw new Error(`Failed to load manifest for url ${result.url} (Status: ${result.status}: ${result.statusText})`)
    try {
      const manifest = await result.json()
      for (const file in manifest) {
        logger.debug(`retrieved ${file} from ${baseUrl}`)
        manifest[file].meta = manifest[file].meta || {}
        manifest[file].meta.baseUrl = baseUrl
      }
      return manifest
    } catch (err) {
      throw new Error(`Failed to load manifest for url ${result.url}: ${err}`)
    }
  }))

  // combine all manifests by keys. With duplicates, last wins
  return viteManifests.reduce((memo, manifest) => Object.assign(memo, manifest), {})
}

export async function getViteManifests ({ version }) {
  let manifests = await cache.get(getRedisKey({ version, name: 'viteManifests' }))
  if (!manifests) {
    manifests = await cache.setAsync(getRedisKey({ version, name: 'viteManifests' }), fetchViteManifests().then(m => JSON.stringify(m)))
  }
  return JSON.parse(manifests)
}

export async function getOxManifests ({ version }) {
  let manifests = await cache.get(getRedisKey({ version, name: 'oxManifests' }))
  if (!manifests) {
    manifests = await cache.setAsync(getRedisKey({ version, name: 'oxManifests' }), (async () => {
      const viteManifests = await getViteManifests({ version })
      return JSON.stringify(viteToOxManifest(viteManifests))
    })())
  }
  return JSON.parse(manifests)
}

export async function getDependencies ({ version }) {
  let deps = await cache.get(getRedisKey({ version, name: 'dependencies' }))
  if (!deps) {
    deps = await await cache.setAsync(getRedisKey({ version, name: 'dependencies' }), (async () => {
      const viteManifests = await getViteManifests({ version })
      return JSON.stringify(viteManifestToDeps(viteManifests))
    })())
  }
  return JSON.parse(deps)
}

export async function getCSSDependenciesFor ({ file, version }) {
  const allDependencies = await getDependencies({ version })
  const dependencies = allDependencies[file] || []
  return dependencies.filter(dep => /\.css/i.test(dep))
}