/*
 *
 * @copyright Copyright (c) OX Software GmbH, Germany <info@open-xchange.com>
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
 *
 * Any use of the work other than as authorized under this license or copyright law is prohibited.
 *
 */

import { configMap } from './config_map.js'
import { getRedisKey, viteManifestToDeps, viteToOxManifest } from './util.js'
import logger from './logger.js'
import * as cache from './cache.js'
import zlib from 'node:zlib'
import { promisify } from 'node:util'
const brotliCompress = promisify(zlib.brotliCompress)

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(configMap.urls.map(async baseUrl => {
    // fetch the manifests
    const result = await fetch(new URL('manifest.json', baseUrl), { cache: 'no-store' })
    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(`[Manifest] 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 }) {
  return cache.get(getRedisKey({ version, name: 'viteManifests' }), async () => [await fetchViteManifests()])
}

export function getOxManifests ({ version }) {
  return cache.getFile({ name: 'oxManifests', version }, async () => {
    const headers = { 'content-type': 'application/json; charset=utf-8', 'content-encoding': 'br' }
    const viteManifests = await getViteManifests({ version })
    const oxManifests = await viteToOxManifest(viteManifests)
    const body = await brotliCompress(JSON.stringify(oxManifests))
    return {
      body,
      headers
    }
  })
}

export function getDependencies ({ version }) {
  return cache.get(getRedisKey({ version, name: 'dependencies' }), async () => {
    const viteManifests = await getViteManifests({ version })
    return [viteManifestToDeps(viteManifests)]
  })
}

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