/*
 * Copyright (C) 2019 StApps
 * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import {SCInternalServerErrorResponse, SCPluginMetaData, SCValidationErrorResponse} from '@openstapps/core';
import {Request} from 'express';
import got from 'got';
import {isTestEnvironment, validator} from '../common.js';
import {backendConfig} from '../config.js';

/**
 * Generic route function used to proxy actual requests to plugins
 * @param request The request for a plugin resource
 * @param plugin Meta data of the plugin
 * @throws {SCInternalServerErrorResponse} On request/response validation or response from the plugin errors
 */
export async function virtualPluginRoute(request: Request, plugin: SCPluginMetaData): Promise<object> {
  try {
    const requestValidation = validator.validate(request.body, plugin.requestSchema);
    if (requestValidation.errors.length > 0) {
      // noinspection ExceptionCaughtLocallyJS
      throw new SCValidationErrorResponse(requestValidation.errors, isTestEnvironment);
    }
    // send the request to the plugin (forward the body) and save the response
    const response = await got.post(plugin.route.replaceAll(/^\//gi, ''), {
      prefixUrl: plugin.address,
      json: request.body,
      timeout: {
        response: backendConfig.backend.externalRequestTimeout,
      },
      responseType: 'json',
    });
    const responseBody = response.body;
    const responseValidation = validator.validate(responseBody, plugin.responseSchema);
    if (responseValidation.errors.length > 0) {
      // noinspection ExceptionCaughtLocallyJS
      throw new SCValidationErrorResponse(responseValidation.errors, isTestEnvironment);
    }
    return responseBody as object;
  } catch (error) {
    // wrap exact error inside of the internal server error response
    throw new SCInternalServerErrorResponse(error, isTestEnvironment);
  }
}
