'use strict';

const api = require('@btst/stack/plugins/api');
const db = require('../db.cjs');
const generator = require('./generator.cjs');
const logo = require('../logo.cjs');

function escapeHtml(str) {
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
}
function escapeJsonForHtml(json) {
  return json.replace(/</g, "\\u003c");
}
function getScalarHTML(schema, theme = "default", nonce) {
  const nonceAttr = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
  const encodedLogo = encodeURIComponent(logo.logo);
  const title = schema.info?.title || "API Reference";
  const description = schema.info?.description || "API Reference";
  return `<!doctype html>
<html>
  <head>
    <title>${escapeHtml(title)}</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <script
      id="api-reference"
      type="application/json"${nonceAttr}>
    ${escapeJsonForHtml(JSON.stringify(schema))}
    <\/script>
    <script${nonceAttr}>
      var configuration = {
        favicon: "data:image/svg+xml;utf8,${encodedLogo}",
        theme: "${theme}",
        metaData: {
          title: ${JSON.stringify(title)},
          description: ${JSON.stringify(description)},
        }
      }

      document.getElementById('api-reference').dataset.configuration =
        JSON.stringify(configuration)
    <\/script>
    <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"${nonceAttr}><\/script>
  </body>
</html>`;
}
const openApiBackendPlugin = (options) => {
  const referencePath = options?.path ?? "/reference";
  let storedContext = null;
  return api.defineBackendPlugin({
    name: "open-api",
    dbPlugin: db.openApiSchema,
    routes: (_adapter, context) => {
      storedContext = context ?? null;
      const generateSchema = api.createEndpoint(
        "/open-api/schema",
        {
          method: "GET"
        },
        async (ctx) => {
          if (!storedContext) {
            throw ctx.error(500, {
              message: "OpenAPI context not available"
            });
          }
          const schema = generator.generateOpenAPISchema(storedContext, {
            title: options?.title,
            description: options?.description,
            version: options?.version
          });
          return schema;
        }
      );
      const reference = api.createEndpoint(
        referencePath,
        {
          method: "GET"
        },
        async (ctx) => {
          if (options?.disableDefaultReference) {
            throw ctx.error(404, {
              message: "Reference page is disabled"
            });
          }
          if (!storedContext) {
            throw ctx.error(500, {
              message: "OpenAPI context not available"
            });
          }
          const schema = generator.generateOpenAPISchema(storedContext, {
            title: options?.title,
            description: options?.description,
            version: options?.version
          });
          return new Response(
            getScalarHTML(schema, options?.theme, options?.nonce),
            {
              headers: {
                "Content-Type": "text/html; charset=utf-8"
              }
            }
          );
        }
      );
      return {
        generateSchema,
        reference
      };
    }
  });
};

exports.openApiBackendPlugin = openApiBackendPlugin;
