'use strict';

// //////////////////////////////////////////////////////////////////////////////
// / DISCLAIMER
// /
// / Copyright 2014-2024 ArangoDB GmbH, Cologne, Germany
// / Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
// /
// / Licensed under the Business Source License 1.1 (the "License");
// / you may not use this file except in compliance with the License.
// / You may obtain a copy of the License at
// /
// /     https://github.com/arangodb/arangodb/blob/devel/LICENSE
// /
// / Unless required by applicable law or agreed to in writing, software
// / distributed under the License is distributed on an "AS IS" BASIS,
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// / See the License for the specific language governing permissions and
// / limitations under the License.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// //////////////////////////////////////////////////////////////////////////////

const NotFound = require('http-errors').NotFound;
const fs = require('fs');
const joinPath = require('path').join;
const normalizePath = require('path').normalize;
const internal = require('internal');
const errors = require('@arangodb').errors;
const FoxxManager = require('@arangodb/foxx/manager');
const swaggerJson = require('@arangodb/foxx/legacy/swagger').swaggerJson;

const NOT_FOUND = errors.ERROR_SERVICE_NOT_FOUND.code;
const SWAGGER_ROOT = fs.join(internal.startupPath, 'server', 'assets', 'swagger');

module.exports = function createSwaggerRouteHandler (foxxMount, opts) {
  if (!opts) {
    opts = {};
  }
  if (typeof opts === 'function') {
    opts = {before: opts};
  }
  if (typeof opts === 'string') {
    opts = {swaggerJson: opts};
  }

  const defaultMount = opts.mount || foxxMount;
  const defaultIndexFile = opts.indexFile || 'index.html';
  const defaultSwaggerRoot = opts.swaggerRoot || SWAGGER_ROOT;
  const defaultSwaggerJsonHandler = opts.swaggerJson || swaggerJson;

  return function (req, res) {
    let mount = defaultMount;
    let indexFile = defaultIndexFile;
    let swaggerRoot = defaultSwaggerRoot;
    if (typeof opts.before === 'function') {
      const result = opts.before.apply(this, arguments);

      if (result === false) {
        return;
      }
      if (result.indexFile) {
        indexFile = result.indexFile;
      }
      if (result.mount) {
        mount = result.mount;
      }
      if (result.swaggerRoot) {
        swaggerRoot = result.swaggerRoot;
      }
    }
    let path = req.suffix;
    if (!path) {
      let params = Object.keys(req._raw.parameters || {}).reduce(function (part, name) {
        return part + encodeURIComponent(name) + '=' + encodeURIComponent(req._raw.parameters[name]) + '&';
      }, '?');
      params = params.slice(0, params.length - 1);
      res.redirect(req.makeAbsolute(req.path + '/index.html') + params);
      return;
    }
    if (path === 'swagger.json') {
      let swaggerJsonHandler = defaultSwaggerJsonHandler;
      if (typeof swaggerJsonHandler === 'string') {
        path = swaggerJsonHandler;
      } else if (typeof swaggerJsonHandler === 'function') {
        let foxx;
        try {
          foxx = FoxxManager.ensureRouted(mount);
        } catch (e) {
          if (e.isArangoError && e.errorNum === NOT_FOUND) {
            throw new NotFound(e.message);
          }
          throw e;
        }
        swaggerJsonHandler(req, res, {mount, foxx});
        return;
      } else if (swaggerJsonHandler && typeof swaggerJsonHandler === 'object') {
        res.json(swaggerJsonHandler);
        return;
      }
    } else if (path === 'index.html') {
      path = indexFile;
    }
    path = normalizePath('/' + path);
    const filePath = joinPath(swaggerRoot, path);
    if (!fs.isFile(filePath)) {
      throw new NotFound(`unknown path "${req._raw.url}"`);
    }
    res.sendFile(filePath);
  };
};
