import fastify from 'fastify'
import formBodyPlugin from '@fastify/formbody'
import urlDataPlugin from '@fastify/url-data'
import fastifySwagger from '@fastify/swagger'
import fastifyMetrics from 'fastify-metrics'
import helmet from '@fastify/helmet'
import yaml from 'js-yaml'
import fs from 'fs'

import versionHandler from './handlers/version.js'
import healthPlugin from './plugins/health.js'
import manifestsPlugin from './plugins/manifests.js'
import metadataPlugin from './plugins/metadata.js'
import redirectsPlugin from './plugins/redirects.js'
import serveFilePlugin from './plugins/serve-files.js'
import { logger } from './logger.js'

const swaggerDocument = yaml.load(fs.readFileSync('./src/swagger.yaml', 'utf8'))

export async function createApp (basePath) {
  const app = fastify({
    logger,
    connectionTimeout: 30000,
    disableRequestLogging: true
  })

  app.addHook('onError', (req, reply, err, done) => {
    const responseTime = reply.getResponseTime()
    reply.log.error({
      res: reply,
      err,
      responseTime
    }, 'request errored')
    done()
  })
  app.addHook('onResponse', (req, reply, done) => {
    const responseTime = reply.getResponseTime()
    reply.log.debug({
      res: reply,
      responseTime
    }, 'request completed')
    done()
  })

  await app.register(formBodyPlugin)
  await app.register(urlDataPlugin)
  await app.register(helmet, {
    contentSecurityPolicy: false,
    crossOriginEmbedderPolicy: false,
    originAgentCluster: false,
    crossOriginOpenerPolicy: { policy: 'same-origin-allow-popups' }
  })
  await app.register(healthPlugin)
  await app.register(fastifyMetrics, {
    routeMetrics: {
      routeBlacklist: ['/ready', '/live', '/health', '/healthy', '/metrics', '/api-docs']
    }
  })
  await app.register(fastifySwagger, {
    routePrefix: '/api-docs',
    prefix: process.env.APP_ROOT,
    swagger: swaggerDocument,
    exposeRoute: process.env.EXPOSE_API_DOCS === 'true'
  })

  await app.addHook('preHandler', versionHandler)

  await app.register(manifestsPlugin, { prefix: process.env.APP_ROOT })
  await app.register(metadataPlugin, { prefix: process.env.APP_ROOT })
  await app.register(redirectsPlugin, { prefix: process.env.APP_ROOT })
  if (process.env.APP_ROOT.length > 1) {
    app.get(process.env.APP_ROOT.slice(0, -1), async (req, res) => {
      res.redirect(process.env.APP_ROOT)
    })
  }

  await app.register(serveFilePlugin)

  return app
}