import { FilteredResponse } from "../../src/types/sdkResponse";
import { flattenObject, isItemInList } from "./helpers";

/**
 * @function callUnomi
 * @param {string} method 
 * @param {string} url 
 * @param {object} body 
 * @param {Record<string, string>} headers 
 * @param {string} successStatus 
 * @param {Array<object>} errors 
 * @returns {FilteredResponse}
 */
export async function callUnomi(method: string, url: string, body: object, headers: Record<string, string>, successStatus: number, errors?: Array<object>): FilteredResponse { // make API call to unomi

    try {

        if (errors) { // check if there is an error code

            return { // return error object result
                statusCode: 500,
                errorMessage: "Validation error.",
                errors: errors,
                exception: null,
                response: {
                    method: method,
                    url: url,
                    body: body,
                    successStatus: successStatus
                }
            };
        }

        let response; // API call response

        if (body === null) { // check if API call has no body
            response = await fetch(url, { // make API call with given parameters
                method: method,
                headers: headers,
                credentials: "omit",
                mode: 'cors',
            });
        }

        else { // API call has a body
            response = await fetch(url, { // make API call with given parameters
                method: method,
                headers: headers,
                body: JSON.stringify(body),
                credentials: "omit",
                mode: 'cors',
            });
        }

        let data = new Object; // object for response data

        if (response.status != 204) { // check if status code is not "No Content success status"
            data = await response.json(); // get response object from unomi
        }

        if (response.status === successStatus) { // check if status code from response is the expected status code of unomi
            return { // return response object in "success" form
                statusCode: response.status,
                responseData: data
            };
        }

        if (response.status === 204 && successStatus === 200 && url.includes("/cxs/segments/")) { // check if we are trying to get a segment that doesn't exist
            return { // return response object in "error" form from unomi side, with a clear errorMessage
                statusCode: response.status,
                errorMessage: "This segment does not exist.",
                errors: [],
                exception: null,
                response: response
            }
        }

        return { // return response object in "error" form from unomi side
            statusCode: response.status,
            errorMessage: "Something went wrong processing this request. Please try again later or contact support if this error persists.",
            errors: [],
            exception: null,
            response: response
        };

    } catch (err) { // error from unomi-sdk side

        return { // return response object in "error" form from unomi-sdk side
            statusCode: 500,
            errorMessage: "Something went wrong processing this request. Please try again later or contact support if this error persists.",
            errors: [],
            exception: err.stack,
            response: {
                method: method,
                url: url,
                body: body,
                successStatus: successStatus
            }
        };
    }
}

/**
 * @function callElasticsearch
 * @param {string} method 
 * @param {string} url 
 * @param {object} body 
 * @param {Record<string, string>} headers 
 * @param {number} successStatus 
 * @param {Array<object>} errors 
 * @returns {FilteredResponse}
 */
export async function callElasticsearch(method: string, url: string, body: object, headers: Record<string, string>, successStatus: number, errors?: Array<object>): FilteredResponse { // make API call to elasticsearch

    try {

        if (errors) { // check if there is an error code

            return { // return error object result
                statusCode: 500,
                errorMessage: "Validation error.",
                errors: errors,
                exception: null,
                response: {
                    method: method,
                    url: url,
                    body: body,
                    successStatus: successStatus
                }
            };
        }

        let response; // API call response

        if (body === null) { // check if API call has no body
            response = await fetch(url, { // make API call with given parameters
                method: method,
                headers: headers,
                credentials: "omit",
                mode: 'cors',
            });
        }

        else { // API call has a body
            response = await fetch(url, { // make API call with given parameters
                method: method,
                headers: headers,
                body: JSON.stringify(body),
                credentials: "omit",
                mode: 'cors',
            });
        }

        if (response.status === successStatus) { // check if status code from response is the expected status code of elasticsearch

            let data = await response.json(); // get response object from elasticsearch
            if (url.endsWith("/context-profile")) { // if we are getting the profile properties
                let responseData = data["context-profile"]["mappings"]["properties"]["properties"]["properties"]; // get profile properties
                let flattenedResponseData = flattenObject(responseData); // flatten profile properties
    
                let temporary_filter = ["jsonld", "mediaCapabilities", "metatags", "microdata", "rdfa"]; // filter for properties which might return in later release
    
                let newFlattenedResponseData: { [key: string]: string } = {} // create empty object
                for (var property in flattenedResponseData) { // iterate over object
                    if (!property.endsWith(".analyzer")) { // if key does not end with .analyzer
                        if (!isItemInList(temporary_filter, property)) { // if key does not contain a word from the temporary filter list | second if-structure so .analyzer won't get checked (improve performance)
                            newFlattenedResponseData[property] = flattenedResponseData[property] // add key and value to new object
                        }
                    }
                }
    
                return { // return response object in "success" form
                    statusCode: response.status,
                    responseData: Object.keys(newFlattenedResponseData)
                };
            } else if (url.endsWith("/context-profile/_count")) { // if we are getting the total amount of profiles
                return { // return response object in "success" form
                    statusCode: response.status,
                    responseData: data.count
                };
            } else {
                return { // return response object in "success" form
                    statusCode: response.status,
                    responseData: {
                        "message": "We don't support this endpoint yet."
                    }
                };
            }

        }    

        return { // return response object in "error" form from elasticsearch side
            statusCode: response.status,
            errorMessage: "Something went wrong processing this request. Please try again later or contact support if this error persists.",
            errors: [],
            exception: null,
            response: response
        };

    } catch (err) { // error from unomi-sdk side

        return { // return response object in "error" form from unomi-sdk side
            statusCode: 500,
            errorMessage: "Something went wrong processing this request. Please try again later or contact support if this error persists.",
            errors: [],
            exception: err.stack,
            response: {
                method: method,
                url: url,
                body: null,
                successStatus: successStatus
            }
        };
    }
}

/**
 * @function callResponse
 * @param {string} method 
 * @param {string} url 
 * @param {any} body 
 * @param {string} successStatus 
 * @returns {FilteredResponse}
 */
export async function callResponse(method: string, url: string, body: any, successStatus: number): FilteredResponse { // simulate API call code for consistency
    try {

        return { // return response object in "success" form
            statusCode: successStatus,
            responseData: body   // list of the keys of the data object
        };

    } catch (err) { // error from unomi-sdk side

        return { // return response object in "error" form from unomi-sdk side
            statusCode: 500,
            errorMessage: "Something went wrong processing this request. Please try again later or contact support if this error persists.",
            errors: [],
            exception: err.stack,
            response: {
                method: method,
                url: url,
                body: null,
                successStatus: successStatus
            }
        };
    }
}

// var flattenObject = function (ob: any) { // flatten given object
//     var toReturn: { [key: string]: string } = {} // result object

//     for (var i in ob) { // go through object
//         if (!ob.hasOwnProperty(i)) continue; // 

//         if ((typeof ob[i]) == 'object') { // check if property is an object
//             if (i != 'fields') { // check if object key is not "fields"
//                 var a = ob[i]; // 

//                 if (ob[i].hasOwnProperty('properties')) { //
//                     a = ob[i]['properties'] // assign value to a
//                 }

//                 var flatObject = flattenObject(a); // 

//                 for (var x in flatObject) { // go through object
//                     if (!flatObject.hasOwnProperty(x)) continue; // 

//                     if (x != 'type') { // check if object key is not "type"
//                         toReturn[i + '.' + x] = flatObject[x]; // 
//                     }

//                     else { // object key is "type"
//                         toReturn[i] = flatObject[x]; // 
//                     }
//                 }
//             }
//         } else { // property is not an object
//             toReturn[i] = ob[i]; // add property to result object
//         }
//     }
//     return toReturn; // return result object
// };

// export function flattenObject(ob: any): any { // flatten given object
//     var toReturn: { [key: string]: string } = {} // result object

//     for (var i in ob) { // go through object
//         if (!ob.hasOwnProperty(i)) continue; // 

//         if ((typeof ob[i]) == 'object') { // check if property is an object
//             if (i != 'fields') { // check if object key is not "fields"
//                 var a = ob[i]; // 

//                 if (ob[i].hasOwnProperty('properties')) { //
//                     a = ob[i]['properties'] // assign value to a
//                 }

//                 var flatObject = flattenObject(a); // 

//                 for (var x in flatObject) { // go through object
//                     if (!flatObject.hasOwnProperty(x)) continue; // 

//                     if (x != 'type') { // check if object key is not "type"
//                         toReturn[i + '.' + x] = flatObject[x]; // 
//                     }

//                     else { // object key is "type"
//                         toReturn[i] = flatObject[x]; // 
//                     }
//                 }
//             }
//         } else { // property is not an object
//             toReturn[i] = ob[i]; // add property to result object
//         }
//     }
//     return toReturn; // return result object
// };