import { PurgeCSS } from 'purgecss'
import { minify } from 'html-minifier'
import { parse } from 'node-html-parser'
import purgeHtml from 'purgecss-from-html'
import path from 'node:path'
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'

/**
 * Transforms the generated HTML markup of a page.
 *
 * Because the error page is uploaded to Fastly, we have to reduce the
 * size of the total markup, as Fastly has a maximum size for error pages
 * (128KB).
 *
 * The method will remove all unused CSS from the file to reduce the size as
 * much as possible.
 */

async function transformFile(folderName: string) {
  const __filename = fileURLToPath(import.meta.url)
  const __dirname = path.dirname(__filename)
  const filePath = path.resolve(
    process.cwd(),
    '.output/public/de/error/index.html',
  )
  // Load the HTML markup.
  const markup = await fs.promises.readFile(filePath).then((v) => v.toString())

  // Parse into DOM.
  const root = parse(markup)

  // Get all style tags.
  const styles = root.querySelectorAll('style')

  // Merge all styles into a single CSS string.
  const css = styles.map((v) => v.innerHTML).join('\n')

  // Runs purge-css to remove all styles that are not used.
  const purgeCSSResult = await new PurgeCSS().purge({
    content: [
      {
        raw: markup,
        extension: 'html',
      },
    ],
    css: [
      {
        raw: css,
      },
    ],
    extractors: [
      {
        extractor: purgeHtml,
        extensions: ['html'],
      },
    ],
    keyframes: false,
  })

  // Create a single CSS string of all the remaining styles.
  const reducedStyles = purgeCSSResult
    .filter((v) => v.css)
    .map((v) => v.css)
    .join('\n')

  // Remove all <style> tags.
  styles.forEach((v) => v.remove())

  // Remove all external styles.
  root.querySelectorAll('link[rel="stylesheet"]').forEach((v) => v.remove())

  // Append the purges CSS to the head.
  root
    .getElementsByTagName('head')[0]
    .appendChild(parse(`<style>${reducedStyles}</style>`))

  // Minifx the final HTML markup.
  const minified = minify(root.toString(), {
    collapseInlineTagWhitespace: true,
    collapseWhitespace: true,
    minifyCSS: true,
    removeComments: true,
    removeRedundantAttributes: true,
  })

  // Write the file in the same location.
  await fs.promises.writeFile(filePath, minified, {
    encoding: 'utf8',
  })
}

async function main() {
  await transformFile('error')
}

main()
