/**
 * Copyright IBM Corp. 2024, 2025
 */
import axios from 'axios';
import FormData from 'form-data';
import { GatewaysJson, IpcError, Logger } from '@apic/studio-shared';
import { AppConstants } from '../constants/app-constants.js';

export const sendToGateway = async (
  gatewayURL: string,
  gatewayUser: string,
  gatewaySecret: string,
  is_mcsp_enabled: boolean,
  zipBuffer: Buffer,
  gatewaysJsonContent: GatewaysJson
) => {
  const formData = new FormData();
  formData.append('file', zipBuffer, 'gatewayInstance.zip');
  formData.append('overwrite', gatewaysJsonContent.overwrite);

  let authorizationHeader;

  if (is_mcsp_enabled) {
    authorizationHeader = `Bearer ${gatewaySecret}`;
  } else {
    const credentials = `${gatewayUser}:${gatewaySecret}`;
    const encodedCredentials = Buffer.from(credentials).toString('base64');
    authorizationHeader = `Basic ${encodedCredentials}`;
  }

  return axios
    .post(gatewayURL + AppConstants.DEPLOY_GATEWAY_URL, formData, {
      headers: {
        ...formData.getHeaders(),
        Authorization: authorizationHeader,
      },
    })
    .then((response) => {
      Logger.debug('Gateway deployment response received', {
        data: JSON.stringify(response.data),
      });
      const processedResponse = ParseAndFindResponse(response);
      if (processedResponse && processedResponse.length) {
        return {
          success: false,
          statusCode: response.status,
          message: 'Api deployment Failed',
          data: response.data,
          errors: processedResponse,
        };
      }
      return {
        success: true,
        statusCode: response.status,
        message: 'Api deployment Successful',
        data: response.data,
        errors: [],
      };
    })
    .catch((error) => {
      let errorMessage =
        error.response?.data?.errorDetails ?? `Response sending to ${gatewayURL}: ${error.message}`;
      let statusCode = error.response ? error.response.status : 404;
      let errors = [errorMessage];

      // Add error logging
      Logger.error(
        'Gateway deployment failed',
        error instanceof Error ? error : new Error(String(error)),
        { gatewayURL, context: 'Gateway Deployment' }
      );

      if (statusCode === 401) {
        errorMessage = 'Unauthorized: Invalid credentials';
        statusCode = 401;
        errors = ['Unauthorized access: Please check your authentication details.'];
      }
      return {
        success: false,
        statusCode,
        message: errorMessage,
        data: null,
        errors,
      };
    });
};

export async function validationManager(url: string, authorizationHeader: string) {
  return axios
    .get(url, {
      timeout: 20000,
      headers: {
        Authorization: authorizationHeader,
      },
    })
    .then((res) => {
      Logger.debug('Gateway validation response', { data: res.data });
      if (res.status === 200) {
        return { data: 'OK', status: 200 };
      } else {
        Logger.warn(`Unexpected status code: ${res.status}`, {
          context: 'Validation',
        });
        throw new IpcError(res.data, res.status);
      }
    })
    .catch((err) => {
      if (err.response) {
        const status = err.response.status;
        const errorData = err.response.data;
        if (status === 401) {
          Logger.error('The user name or password did not match.', err, {
            context: 'Authorization',
          });
          throw new IpcError('The user name or password did not match.', 401, errorData);
        } else if (status === 502) {
          Logger.error('Bad Gateway.', err, { context: 'Validation' });
          throw new IpcError('Bad Gateway', 502);
        } else if (status === 404) {
          Logger.error('Gateway not found.', err, { context: 'Validation' });
          throw new IpcError('Gateway not found', 404);
        } else {
          Logger.error(`Validation failed with status: ${status}`, err, {
            context: 'Validation',
            errorData,
          });
          throw new IpcError(errorData, status);
        }
      } else if (err.code === 'ECONNABORTED') {
        Logger.error('Request timed out.', err, { context: 'Validation' });
        throw new IpcError('Request timed out', 408);
      } else if (
        err.message?.includes('SSL') ||
        err.message?.includes('certificate') ||
        err.code === 'ERR_SSL_CERT'
      ) {
        Logger.error('SSL certificate validation failed.', err, { context: 'Validation' });
        throw new IpcError(
          'SSL certificate validation failed.',
          495,
          'SSL certificate validation failed.'
        );
      } else if (err.code === 'ENOTFOUND') {
        Logger.error('Error: Could not resolve host name', err, { context: 'Validation' });
        throw new IpcError(
          'Error: Could not resolve host name',
          404,
          'Error: Could not resolve host name'
        );
      } else if (err.code === 'ECONNREFUSED') {
        Logger.error(
          'Error: Gateway refused to connect. Please verify the service availability.',
          err,
          { context: 'Validation' }
        );
        throw new IpcError(
          'Error: Gateway refused to connect. Please verify the service availability.',
          503,
          'Error: Gateway refused to connect. Please verify the service availability.'
        );
      } else {
        Logger.error('Gateway validation failed', err, { context: 'Validation' });
        throw new IpcError('Something went wrong while validating the gateway.', 500);
      }
    });
}

export function ParseAndFindResponse(response: any) {
  const failedExplanations: string[] = [];

  if (response?.data?.StudioResult && Array.isArray(response.data.StudioResult)) {
    for (const item of response.data.StudioResult) {
      if (item && typeof item === 'object') {
        const apiKey = Object.keys(item).find((key) => key.toLowerCase() === 'api');

        if (apiKey && item[apiKey]) {
          const api = item[apiKey];
          if (api.status === 'Failed' && api.explanation) {
            failedExplanations.push(api.explanation);
          }
        }
      }
    }
  }

  return failedExplanations;
}
