/**
 * @description Represents an HTTP client for API
 * @param baseAddress The base address of the HTTP client.
 * @param defaultSettings The default settings for the HTTP client.
 */
declare function HttpClient(baseAddress?: string, defaultSettings?: DefaultSettings): void;

interface HttpClient {
    /**
     * Sends an HTTP POST request to the specified relative address.
     * 
     * @param {string} relativeAddress - The relative address to send the request to.
     * @param {any} value - The data to send with the request (optional).
     * @param {RequestSettings} requestSettings - The additional settings for the request (optional).
     * @returns {Promise<T>} A promise that resolves with the response data if the request is successful, or rejects with an error message if the request fails.
     */
    httpPost: <T>(relativeAddress: string, value?: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Performs an HTTP GET request.
     * 
     * @param {string} relativeAddress - The relative address of the resource.
     * @param {RequestSettings} requestSettings - The settings for the request.
     * @returns {Promise<T>} - A promise that resolves with the response data.
     */
    httpGet: <T>(relativeAddress: string, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP PUT request to the specified relative address.
     * 
     * @param {string} relativeAddress - The relative address to send the request to.
     * @param {any} value - The data to send in the request body.
     * @param {RequestSettings} requestSettings - Additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the response data if the request is successful, or rejects with an error message if the request fails.
     */
    httpPut: <T>(relativeAddress: string, value?: any, requestSettings?: any) => Promise<T>;

    /**
     * Sends an HTTP PUT request and returns the full response.
     * @param {string} relativeAddress - The relative address of the API endpoint.
     * @param {any} value - The data to be sent in the request body.
     * @param {RequestSettings} requestSettings - Additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the full response or rejects with an error.
     */
    httpPut_FullResponse: <T>(relativeAddress: string, value?: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP PATCH request to the specified relative address.
     * 
     * @param {string} relativeAddress - The relative address to send the request to.
     * @param {any} value - The value to be sent in the request body.
     * @param {RequestSettings} requestSettings - Additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the response data if the request is successful, or rejects with an error message if the request fails.
     */
    httpPatch: <T>(relativeAddress: string, value?: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP DELETE request to the specified relative address.
     * 
     * @param {string} relativeAddress - The relative address to send the DELETE request to.
     * @param {any} content - The content to include in the request body.
     * @param {requestSettRequestSettingsings} requestSettings - The additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the response data if the request is successful, or rejects with an error message if the request fails.
     */
    httpDelete: <T>(relativeAddress: string, content?: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP POST request with JSON data.
     * @param {string} relativeUrl - The relative URL to send the request to.
     * @param {any} value - The JSON data to send in the request body.
     * @param {RequestSettings} requestSettings - Additional settings for the request (optional).
     * @returns {Promise<T>} A promise that resolves with the response JSON or rejects with an error.
     */
    httpPostJSON: <T>(relativeUrl: string, value: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * sends an HTTP POST request with JSON data and returns the full response.
     * @param {string} relativeAddress - The relative address of the resource.
     * @param {any} value - The data to send with the request.
     * @param {RequestSettings} requestSettings - Additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the full response.
     */
    httpPostJSONFullResponse: <T>(relativeAddress: string, value: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP GET request and returns the response as JSON.
     * @param {string} relativeUrl - The relative URL to send the GET request to.
     * @param {RequestSettings} requestSettings - Additional settings for the request (optional).
     * @returns {Promise<T>} - A promise that resolves with the JSON response.
     */
    httpGetJSON: <T>(relativeUrl: string, requestSettings?: RequestSettings) => Promise<T>;

    /**AxiosHeaders | 
     * Sends an HTTP PUT request with JSON data.
     * @param {string} relativeUrl - The relative URL to send the request to.
     * @param {any} value - The JSON data to send in the request body.
     * @param {RequestSettings} requestSettings - Additional settings for the request (optional).
     * @returns {Promise<T>} - A promise that resolves with the response data.
     */
    httpPutJSON: <T>(relativeUrl: string, value: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP PATCH request with JSON payload.
     * @param {string} relativeUrl - The relative URL to send the request to.
     * @param {any} value - The JSON payload to send with the request.
     * @param {RequestSettings} requestSettings - Additional settings for the request (optional).
     * @returns {Promise<T>} A promise that resolves with the parsed JSON response, or undefined if the response is empty.
     */
    httpPatchJSON: <T>(relativeUrl: string, value: any, requestSettings?: RequestSettings) => Promise<T>;

    /**
     * Sends an HTTP DELETE request and returns the response as JSON.
     * @param {string} relativeUrl - The relative URL for the request.
     * @param {any} content - The content to send with the request (optional).
     * @param {RequestSettings} requestSettings - Additional settings for the request (optional).
     * @returns {Promise<T>} A promise that resolves with the parsed JSON response, or undefined if the response is empty.
     */
    httpDeleteJSON: <T>(relativeUrl: string, content?: any, requestSettings?: RequestSettings) => Promise<T>

    /**
     * Deletes a resource and returns the full response.
     * @param {string} relativeAddress - The relative address of the resource.
     * @param {any} content - The content to send with the request.
     * @param {RequestSettings} requestSettings - Additional settings for the request.
     * @returns {Promise<T>} A promise that resolves with the full response.
     */
    httpDeleteJSONFullResponse: <T>(relativeAddress: string, content?: any, requestSettings?: RequestSettings) => Promise<T>;
}

export default HttpClient;

type CommonRequestHeadersList = 'Accept' | 'Content-Length' | 'User-Agent' | 'Content-Encoding' | 'Authorization';
type ContentType = 'text/html' | 'text/plain' | 'multipart/form-data' | 'application/json' | 'application/x-www-form-urlencoded' | 'application/octet-stream';
export type RequestHeaders = {
    [Key in CommonRequestHeadersList]?: string | string[] | number | boolean | null;
} & {
    'Content-Type'?: ContentType
};

/**
 * Represents the configuration options for an HTTP request.
 */
export interface RequestSettings {
    /**
     * `headers` are custom headers to be sent
     */
    headers?: RequestHeaders;
}

/**
 * Represents the default configuration options for an HTTP request.
 */
export interface DefaultSettings {
    /**
     * `headers` are custom headers to be sent
     */
    headers?: RequestHeaders;

    /** 
     *`timeout` specifies the number of milliseconds before the request times out.
     * If the request takes longer than `timeout`, the request will be aborted.
     */
    timeout?: number;
}