import get from 'lodash/get';
import each from 'lodash/each';
import find from 'lodash/find';
import findIndex from 'lodash/findIndex';
import isString from 'lodash/isString';
import map from 'lodash/map';
import filter from 'lodash/filter';
import sortBy from 'lodash/sortBy';
import isEqual from 'lodash/isEqual';
import cloneDeep from 'lodash/cloneDeep';
import { uuid } from 'utils/common';
import path from 'path';
import slash from 'utils/common/slash';

const replaceTabsWithSpaces = (str, numSpaces = 2) => {
  if (!str || !str.length || !isString(str)) {
    return '';
  }

  return str.replaceAll('\t', ' '.repeat(numSpaces));
};

export const addDepth = (items = []) => {
  const depth = (itms, initialDepth) => {
    each(itms, (i) => {
      i.depth = initialDepth;

      if (i.items && i.items.length) {
        depth(i.items, initialDepth + 1);
      }
    });
  };

  depth(items, 1);
};

export const collapseCollection = (collection) => {
  collection.collapsed = true;

  const collapseItem = (items) => {
    each(items, (i) => {
      i.collapsed = true;

      if (i.items && i.items.length) {
        collapseItem(i.items);
      }
    });
  };

  collapseItem(collection.items, 1);
};

export const sortItems = (collection) => {
  const sort = (obj) => {
    if (obj.items && obj.items.length) {
      obj.items = sortBy(obj.items, 'type');
    }

    each(obj.items, (i) => sort(i));
  };

  sort(collection);
};

export const flattenItems = (items = []) => {
  const flattenedItems = [];

  const flatten = (itms, flattened) => {
    each(itms, (i) => {
      flattened.push(i);

      if (i.items && i.items.length) {
        flatten(i.items, flattened);
      }
    });
  };

  flatten(items, flattenedItems);

  return flattenedItems;
};

export const findItem = (items = [], itemUid) => {
  return find(items, (i) => i.uid === itemUid);
};

export const findCollectionByUid = (collections, collectionUid) => {
  return find(collections, (c) => c.uid === collectionUid);
};

export const findCollectionByPathname = (collections, pathname) => {
  return find(collections, (c) => c.pathname === pathname);
};

export const findCollectionByItemUid = (collections, itemUid) => {
  return find(collections, (c) => {
    return findItemInCollection(c, itemUid);
  });
};

export const findItemByPathname = (items = [], pathname) => {
  return find(items, (i) => slash(i.pathname) === slash(pathname));
};

export const findItemInCollectionByPathname = (collection, pathname) => {
  let flattenedItems = flattenItems(collection.items);

  return findItemByPathname(flattenedItems, pathname);
};

export const findItemInCollection = (collection, itemUid) => {
  let flattenedItems = flattenItems(collection.items);

  return findItem(flattenedItems, itemUid);
};

export const findParentItemInCollection = (collection, itemUid) => {
  let flattenedItems = flattenItems(collection.items);

  return find(flattenedItems, (item) => {
    return item.items && find(item.items, (i) => i.uid === itemUid);
  });
};

export const recursivelyGetAllItemUids = (items = []) => {
  let flattenedItems = flattenItems(items);

  return map(flattenedItems, (i) => i.uid);
};

export const findEnvironmentInCollection = (collection, envUid) => {
  return find(collection.environments, (e) => e.uid === envUid);
};

export const findEnvironmentInCollectionByName = (collection, name) => {
  return find(collection.environments, (e) => e.name === name);
};

export const moveCollectionItem = (collection, draggedItem, targetItem) => {
  let draggedItemParent = findParentItemInCollection(collection, draggedItem.uid);

  if (draggedItemParent) {
    draggedItemParent.items = sortBy(draggedItemParent.items, (item) => item.seq);
    draggedItemParent.items = filter(draggedItemParent.items, (i) => i.uid !== draggedItem.uid);
    draggedItem.pathname = path.join(draggedItemParent.pathname, draggedItem.filename);
  } else {
    collection.items = sortBy(collection.items, (item) => item.seq);
    collection.items = filter(collection.items, (i) => i.uid !== draggedItem.uid);
  }

  if (targetItem.type === 'folder') {
    targetItem.items = sortBy(targetItem.items || [], (item) => item.seq);
    targetItem.items.push(draggedItem);
    draggedItem.pathname = path.join(targetItem.pathname, draggedItem.filename);
  } else {
    let targetItemParent = findParentItemInCollection(collection, targetItem.uid);

    if (targetItemParent) {
      targetItemParent.items = sortBy(targetItemParent.items, (item) => item.seq);
      let targetItemIndex = findIndex(targetItemParent.items, (i) => i.uid === targetItem.uid);
      targetItemParent.items.splice(targetItemIndex + 1, 0, draggedItem);
      draggedItem.pathname = path.join(targetItemParent.pathname, draggedItem.filename);
    } else {
      collection.items = sortBy(collection.items, (item) => item.seq);
      let targetItemIndex = findIndex(collection.items, (i) => i.uid === targetItem.uid);
      collection.items.splice(targetItemIndex + 1, 0, draggedItem);
      draggedItem.pathname = path.join(collection.pathname, draggedItem.filename);
    }
  }
};

export const moveCollectionItemToRootOfCollection = (collection, draggedItem) => {
  let draggedItemParent = findParentItemInCollection(collection, draggedItem.uid);

  // If the dragged item is already at the root of the collection, do nothing
  if (!draggedItemParent) {
    return;
  }

  draggedItemParent.items = sortBy(draggedItemParent.items, (item) => item.seq);
  draggedItemParent.items = filter(draggedItemParent.items, (i) => i.uid !== draggedItem.uid);
  collection.items = sortBy(collection.items, (item) => item.seq);
  collection.items.push(draggedItem);
  if (draggedItem.type == 'folder') {
    draggedItem.pathname = path.join(collection.pathname, draggedItem.name);
  } else {
    draggedItem.pathname = path.join(collection.pathname, draggedItem.filename);
  }
};

export const getItemsToResequence = (parent, collection) => {
  let itemsToResequence = [];

  if (!parent) {
    let index = 1;
    each(collection.items, (item) => {
      if (isItemARequest(item)) {
        itemsToResequence.push({
          pathname: item.pathname,
          seq: index++
        });
      }
    });
    return itemsToResequence;
  }

  if (parent.items && parent.items.length) {
    let index = 1;
    each(parent.items, (item) => {
      if (isItemARequest(item)) {
        itemsToResequence.push({
          pathname: item.pathname,
          seq: index++
        });
      }
    });
    return itemsToResequence;
  }

  return itemsToResequence;
};

export const transformCollectionToSaveToExportAsFile = (collection, options = {}) => {
  const copyHeaders = (headers) => {
    return map(headers, (header) => {
      return {
        uid: header.uid,
        name: header.name,
        value: header.value,
        description: header.description,
        enabled: header.enabled
      };
    });
  };

  const copyParams = (params) => {
    return map(params, (param) => {
      return {
        uid: param.uid,
        name: param.name,
        value: param.value,
        description: param.description,
        type: param.type,
        enabled: param.enabled
      };
    });
  };

  const copyFormUrlEncodedParams = (params = []) => {
    return map(params, (param) => {
      return {
        uid: param.uid,
        name: param.name,
        value: param.value,
        description: param.description,
        enabled: param.enabled
      };
    });
  };

  const copyMultipartFormParams = (params = []) => {
    return map(params, (param) => {
      return {
        uid: param.uid,
        type: param.type,
        name: param.name,
        value: param.value,
        description: param.description,
        enabled: param.enabled
      };
    });
  };

  const copyItems = (sourceItems, destItems) => {
    each(sourceItems, (si) => {
      if (!isItemAFolder(si) && !isItemARequest(si) && si.type !== 'js') {
        return;
      }

      const di = {
        uid: si.uid,
        type: si.type,
        name: si.name,
        seq: si.seq
      };

      if (si.request) {
        di.request = {
          url: si.request.url,
          method: si.request.method,
          headers: copyHeaders(si.request.headers),
          params: copyParams(si.request.params),
          body: {
            mode: si.request.body.mode,
            json: si.request.body.json,
            text: si.request.body.text,
            xml: si.request.body.xml,
            graphql: si.request.body.graphql,
            sparql: si.request.body.sparql,
            formUrlEncoded: copyFormUrlEncodedParams(si.request.body.formUrlEncoded),
            multipartForm: copyMultipartFormParams(si.request.body.multipartForm)
          },
          script: si.request.script,
          vars: si.request.vars,
          assertions: si.request.assertions,
          tests: si.request.tests,
          docs: si.request.docs
        };

        // Handle auth object dynamically
        di.request.auth = {
          mode: get(si.request, 'auth.mode', 'none')
        };

        switch (di.request.auth.mode) {
          case 'awsv4':
            di.request.auth.awsv4 = {
              accessKeyId: get(si.request, 'auth.awsv4.accessKeyId', ''),
              secretAccessKey: get(si.request, 'auth.awsv4.secretAccessKey', ''),
              sessionToken: get(si.request, 'auth.awsv4.sessionToken', ''),
              service: get(si.request, 'auth.awsv4.service', ''),
              region: get(si.request, 'auth.awsv4.region', ''),
              profileName: get(si.request, 'auth.awsv4.profileName', '')
            };
            break;
          case 'basic':
            di.request.auth.basic = {
              username: get(si.request, 'auth.basic.username', ''),
              password: get(si.request, 'auth.basic.password', '')
            };
            break;
          case 'bearer':
            di.request.auth.bearer = {
              token: get(si.request, 'auth.bearer.token', '')
            };
            break;
          case 'digest':
            di.request.auth.digest = {
              username: get(si.request, 'auth.digest.username', ''),
              password: get(si.request, 'auth.digest.password', '')
            };
            break;
          case 'oauth2':
            let grantType = get(si.request, 'auth.oauth2.grantType', '');
            switch (grantType) {
              case 'password':
                di.request.auth.oauth2 = {
                  grantType: grantType,
                  accessTokenUrl: get(si.request, 'auth.oauth2.accessTokenUrl', ''),
                  username: get(si.request, 'auth.oauth2.username', ''),
                  password: get(si.request, 'auth.oauth2.password', ''),
                  clientId: get(si.request, 'auth.oauth2.clientId', ''),
                  clientSecret: get(si.request, 'auth.oauth2.clientSecret', ''),
                  scope: get(si.request, 'auth.oauth2.scope', '')
                };
                break;
              case 'authorization_code':
                di.request.auth.oauth2 = {
                  grantType: grantType,
                  callbackUrl: get(si.request, 'auth.oauth2.callbackUrl', ''),
                  authorizationUrl: get(si.request, 'auth.oauth2.authorizationUrl', ''),
                  accessTokenUrl: get(si.request, 'auth.oauth2.accessTokenUrl', ''),
                  clientId: get(si.request, 'auth.oauth2.clientId', ''),
                  clientSecret: get(si.request, 'auth.oauth2.clientSecret', ''),
                  scope: get(si.request, 'auth.oauth2.scope', ''),
                  pkce: get(si.request, 'auth.oauth2.pkce', false)
                };
                break;
              case 'client_credentials':
                di.request.auth.oauth2 = {
                  grantType: grantType,
                  accessTokenUrl: get(si.request, 'auth.oauth2.accessTokenUrl', ''),
                  clientId: get(si.request, 'auth.oauth2.clientId', ''),
                  clientSecret: get(si.request, 'auth.oauth2.clientSecret', ''),
                  scope: get(si.request, 'auth.oauth2.scope', '')
                };
                break;
            }
            break;
          case 'apikey':
            di.request.auth.apikey = {
              key: get(si.request, 'auth.apikey.key', ''),
              value: get(si.request, 'auth.apikey.value', ''),
              placement: get(si.request, 'auth.apikey.placement', 'header')
            };
            break;
          case 'wsse':
            di.request.auth.wsse = {
              username: get(si.request, 'auth.wsse.username', ''),
              password: get(si.request, 'auth.wsse.password', '')
            };
            break;
          default:
            break;
        }

        if (di.request.body.mode === 'json') {
          di.request.body.json = replaceTabsWithSpaces(di.request.body.json);
        }
      }

      if (si.type == 'folder' && si?.root) {
        di.root = {
          request: {}
        };

        let { request, meta, docs } = si?.root || {};
        let { headers, script = {}, vars = {}, tests } = request || {};

        // folder level headers
        if (headers?.length) {
          di.root.request.headers = headers;
        }
        // folder level script
        if (Object.keys(script)?.length) {
          di.root.request.script = {};
          if (script?.req?.length) {
            di.root.request.script.req = script?.req;
          }
          if (script?.res?.length) {
            di.root.request.script.res = script?.res;
          }
        }
        // folder level vars
        if (Object.keys(vars)?.length) {
          di.root.request.vars = {};
          if (vars?.req?.length) {
            di.root.request.vars.req = vars?.req;
          }
          if (vars?.res?.length) {
            di.root.request.vars.res = vars?.res;
          }
        }
        // folder level tests
        if (tests?.length) {
          di.root.request.tests = tests;
        }

        // folder level docs
        if (docs?.length) {
          di.root.docs = docs;
        }

        if (meta?.name) {
          di.root.meta = {};
          di.root.meta.name = meta?.name;
        }
        if (!Object.keys(di.root.request)?.length) {
          delete di.root.request;
        }
        if (!Object.keys(di.root)?.length) {
          delete di.root;
        }
      }

      if (si.type === 'js') {
        di.fileContent = si.raw;
      }

      destItems.push(di);

      if (si.items && si.items.length) {
        di.items = [];
        copyItems(si.items, di.items);
      }
    });
  };

  const collectionToSave = {};
  collectionToSave.name = collection.name;
  collectionToSave.uid = collection.uid;

  // todo: move this to the place where collection gets created
  collectionToSave.version = '1';
  collectionToSave.items = [];
  collectionToSave.activeEnvironmentUid = collection.activeEnvironmentUid;
  collectionToSave.environments = collection.environments || [];

  collectionToSave.root = {
    request: {}
  };

  let { request, docs, meta } = collection?.root || {};
  let { auth, headers, script = {}, vars = {}, tests } = request || {};

  // collection level auth
  if (auth?.mode) {
    collectionToSave.root.request.auth = auth;
  }
  // collection level headers
  if (headers?.length) {
    collectionToSave.root.request.headers = headers;
  }
  // collection level script
  if (Object.keys(script)?.length) {
    collectionToSave.root.request.script = {};
    if (script?.req?.length) {
      collectionToSave.root.request.script.req = script?.req;
    }
    if (script?.res?.length) {
      collectionToSave.root.request.script.res = script?.res;
    }
  }
  // collection level vars
  if (Object.keys(vars)?.length) {
    collectionToSave.root.request.vars = {};
    if (vars?.req?.length) {
      collectionToSave.root.request.vars.req = vars?.req;
    }
    if (vars?.res?.length) {
      collectionToSave.root.request.vars.res = vars?.res;
    }
  }
  // collection level tests
  if (tests?.length) {
    collectionToSave.root.request.tests = tests;
  }
  // collection level docs
  if (docs?.length) {
    collectionToSave.root.docs = docs;
  }
  if (meta?.name) {
    collectionToSave.root.meta = {};
    collectionToSave.root.meta.name = meta?.name;
  }
  if (!Object.keys(collectionToSave.root.request)?.length) {
    delete collectionToSave.root.request;
  }
  if (!Object.keys(collectionToSave.root)?.length) {
    delete collectionToSave.root;
  }

  collectionToSave.brunoConfig = cloneDeep(collection?.brunoConfig);

  // delete proxy password if present
  if (collectionToSave?.brunoConfig?.proxy?.auth?.password) {
    delete collectionToSave.brunoConfig.proxy.auth.password;
  }

  copyItems(collection.items, collectionToSave.items);
  return collectionToSave;
};

export const transformRequestToSaveToFilesystem = (item) => {
  const _item = item.draft ? item.draft : item;
  const itemToSave = {
    uid: _item.uid,
    type: _item.type,
    name: _item.name,
    seq: _item.seq,
    request: {
      method: _item.request.method,
      url: _item.request.url,
      params: [],
      headers: [],
      auth: _item.request.auth,
      body: _item.request.body,
      script: _item.request.script,
      vars: _item.request.vars,
      assertions: _item.request.assertions,
      tests: _item.request.tests,
      docs: _item.request.docs
    }
  };

  each(_item.request.params, (param) => {
    itemToSave.request.params.push({
      uid: param.uid,
      name: param.name,
      value: param.value,
      description: param.description,
      type: param.type,
      enabled: param.enabled
    });
  });

  each(_item.request.headers, (header) => {
    itemToSave.request.headers.push({
      uid: header.uid,
      name: header.name,
      value: header.value,
      description: header.description,
      enabled: header.enabled
    });
  });

  if (itemToSave.request.body.mode === 'json') {
    itemToSave.request.body = {
      ...itemToSave.request.body,
      json: replaceTabsWithSpaces(itemToSave.request.body.json)
    };
  }

  return itemToSave;
};

// todo: optimize this
export const deleteItemInCollection = (itemUid, collection) => {
  collection.items = filter(collection.items, (i) => i.uid !== itemUid);

  let flattenedItems = flattenItems(collection.items);
  each(flattenedItems, (i) => {
    if (i.items && i.items.length) {
      i.items = filter(i.items, (i) => i.uid !== itemUid);
    }
  });
};

export const deleteItemInCollectionByPathname = (pathname, collection) => {
  collection.items = filter(collection.items, (i) => i.pathname !== pathname);

  let flattenedItems = flattenItems(collection.items);
  each(flattenedItems, (i) => {
    if (i.items && i.items.length) {
      i.items = filter(i.items, (i) => i.pathname !== pathname);
    }
  });
};

export const isItemARequest = (item) => {
  return item.hasOwnProperty('request') && ['http-request', 'graphql-request'].includes(item.type) && !item.items;
};

export const isItemAFolder = (item) => {
  return !item.hasOwnProperty('request') && item.type === 'folder';
};

export const humanizeRequestBodyMode = (mode) => {
  let label = 'No Body';
  switch (mode) {
    case 'json': {
      label = 'JSON';
      break;
    }
    case 'text': {
      label = 'TEXT';
      break;
    }
    case 'xml': {
      label = 'XML';
      break;
    }
    case 'sparql': {
      label = 'SPARQL';
      break;
    }
    case 'formUrlEncoded': {
      label = 'Form URL Encoded';
      break;
    }
    case 'multipartForm': {
      label = 'Multipart Form';
      break;
    }
  }

  return label;
};

export const humanizeRequestAuthMode = (mode) => {
  let label = 'No Auth';
  switch (mode) {
    case 'inherit': {
      label = 'Inherit';
      break;
    }
    case 'awsv4': {
      label = 'AWS Sig V4';
      break;
    }
    case 'basic': {
      label = 'Basic Auth';
      break;
    }
    case 'bearer': {
      label = 'Bearer Token';
      break;
    }
    case 'digest': {
      label = 'Digest Auth';
      break;
    }
    case 'oauth2': {
      label = 'OAuth 2.0';
      break;
    }
    case 'wsse': {
      label = 'WSSE Auth';
      break;
    }
    case 'apikey': {
      label = 'API Key';
      break;
    }
  }

  return label;
};

export const humanizeRequestAPIKeyPlacement = (placement) => {
  let label = 'Header';
  switch (placement) {
    case 'header': {
      label = 'Header';
      break;
    }
    case 'queryparams': {
      label = 'Query Params';
      break;
    }
  }

  return label;
};

export const humanizeGrantType = (mode) => {
  let label = 'No Auth';
  switch (mode) {
    case 'password': {
      label = 'Password Credentials';
      break;
    }
    case 'authorization_code': {
      label = 'Authorization Code';
      break;
    }
    case 'client_credentials': {
      label = 'Client Credentials';
      break;
    }
  }

  return label;
};

export const refreshUidsInItem = (item) => {
  item.uid = uuid();

  each(get(item, 'request.headers'), (header) => (header.uid = uuid()));
  each(get(item, 'request.params'), (param) => (param.uid = uuid()));
  each(get(item, 'request.body.multipartForm'), (param) => (param.uid = uuid()));
  each(get(item, 'request.body.formUrlEncoded'), (param) => (param.uid = uuid()));

  return item;
};

export const deleteUidsInItem = (item) => {
  delete item.uid;
  const params = get(item, 'request.params', []);
  const headers = get(item, 'request.headers', []);
  const bodyFormUrlEncoded = get(item, 'request.body.formUrlEncoded', []);
  const bodyMultipartForm = get(item, 'request.body.multipartForm', []);

  params.forEach((param) => delete param.uid);
  headers.forEach((header) => delete header.uid);
  bodyFormUrlEncoded.forEach((param) => delete param.uid);
  bodyMultipartForm.forEach((param) => delete param.uid);

  return item;
};

export const areItemsTheSameExceptSeqUpdate = (_item1, _item2) => {
  let item1 = cloneDeep(_item1);
  let item2 = cloneDeep(_item2);

  // remove seq from both items
  delete item1.seq;
  delete item2.seq;

  // remove draft from both items
  delete item1.draft;
  delete item2.draft;

  // get projection of both items
  item1 = transformRequestToSaveToFilesystem(item1);
  item2 = transformRequestToSaveToFilesystem(item2);

  // delete uids from both items
  deleteUidsInItem(item1);
  deleteUidsInItem(item2);

  return isEqual(item1, item2);
};

export const getDefaultRequestPaneTab = (item) => {
  if (item.type === 'http-request') {
    return 'params';
  }

  if (item.type === 'graphql-request') {
    return 'query';
  }
};

export const getGlobalEnvironmentVariables = ({ globalEnvironments, activeGlobalEnvironmentUid }) => {
  let variables = {};
  const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid);
  if (environment) {
    each(environment.variables, (variable) => {
      if (variable.name && variable.enabled) {
        variables[variable.name] = variable.value;
      }
    });
  }
  return variables;
};

export const getGlobalEnvironmentVariablesMasked = ({ globalEnvironments, activeGlobalEnvironmentUid }) => {
  const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid);

  if (environment && Array.isArray(environment.variables)) {
    return environment.variables
      .filter((variable) => variable.name && variable.value && variable.enabled && variable.secret)
      .map((variable) => variable.name);
  }

  return [];
};


export const getEnvironmentVariables = (collection) => {
  let variables = {};
  if (collection) {
    const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
    if (environment) {
      each(environment.variables, (variable) => {
        if (variable.name && variable.value && variable.enabled) {
          variables[variable.name] = variable.value;
        }
      });
    }
  }

  return variables;
};

export const getEnvironmentVariablesMasked = (collection) => {
  // Return an empty array if the collection is invalid or not provided
  if (!collection || !collection.activeEnvironmentUid) {
    return [];
  }

  // Find the active environment in the collection
  const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
  if (!environment || !environment.variables) {
    return [];
  }

  // Filter the environment variables to get only the masked (secret) ones
  return environment.variables
    .filter((variable) => variable.name && variable.value && variable.enabled && variable.secret)
    .map((variable) => variable.name);
};

const getPathParams = (item) => {
  let pathParams = {};
  if (item && item.request && item.request.params) {
    item.request.params.forEach((param) => {
      if (param.type === 'path' && param.name && param.value) {
        pathParams[param.name] = param.value;
      }
    });
  }
  return pathParams;
};

export const getTotalRequestCountInCollection = (collection) => {
  let count = 0;
  each(collection.items, (item) => {
    if (isItemARequest(item)) {
      count++;
    } else if (isItemAFolder(item)) {
      count += getTotalRequestCountInCollection(item);
    }
  });

  return count;
};

export const getAllVariables = (collection, item) => {
  if(!collection) return {};
  const envVariables = getEnvironmentVariables(collection);
  const requestTreePath = getTreePathFromCollectionToItem(collection, item);
  let { collectionVariables, folderVariables, requestVariables } = mergeVars(collection, requestTreePath);
  const pathParams = getPathParams(item);
  const { globalEnvironmentVariables = {} } = collection;

  const { processEnvVariables = {}, runtimeVariables = {} } = collection;
  const mergedVariables = {
    ...folderVariables,
    ...requestVariables,
    ...runtimeVariables
  };

  const mergedVariablesGlobal = {
    ...collectionVariables,
    ...envVariables,
    ...folderVariables,
    ...requestVariables,
    ...runtimeVariables,
  }

  const maskedEnvVariables = getEnvironmentVariablesMasked(collection) || [];
  const maskedGlobalEnvVariables = collection?.globalEnvSecrets || [];

  const filteredMaskedEnvVariables = maskedEnvVariables.filter((key) => !(key in mergedVariables));
  const filteredMaskedGlobalEnvVariables = maskedGlobalEnvVariables.filter((key) => !(key in mergedVariablesGlobal));

  const uniqueMaskedVariables = [...new Set([...filteredMaskedEnvVariables, ...filteredMaskedGlobalEnvVariables])];

  return {
    ...globalEnvironmentVariables,
    ...collectionVariables,
    ...envVariables,
    ...folderVariables,
    ...requestVariables,
    ...runtimeVariables,
    pathParams: {
      ...pathParams
    },
    maskedEnvVariables: uniqueMaskedVariables,
    process: {
      env: {
        ...processEnvVariables
      }
    }
  };
};

export const maskInputValue = (value) => {
  if (!value || typeof value !== 'string') {
    return '';
  }

  return value
    .split('')
    .map(() => '*')
    .join('');
};

const getTreePathFromCollectionToItem = (collection, _item) => {
  let path = [];
  let item = findItemInCollection(collection, _item?.uid);
  while (item) {
    path.unshift(item);
    item = findParentItemInCollection(collection, item?.uid);
  }
  return path;
};

const mergeVars = (collection, requestTreePath = []) => {
  let collectionVariables = {};
  let folderVariables = {};
  let requestVariables = {};
  let collectionRequestVars = get(collection, 'root.request.vars.req', []);
  collectionRequestVars.forEach((_var) => {
    if (_var.enabled) {
      collectionVariables[_var.name] = _var.value;
    }
  });
  for (let i of requestTreePath) {
    if (i.type === 'folder') {
      let vars = get(i, 'root.request.vars.req', []);
      vars.forEach((_var) => {
        if (_var.enabled) {
          folderVariables[_var.name] = _var.value;
        }
      });
    } else {
      let vars = get(i, 'request.vars.req', []);
      vars.forEach((_var) => {
        if (_var.enabled) {
          requestVariables[_var.name] = _var.value;
        }
      });
    }
  }
  return {
    collectionVariables,
    folderVariables,
    requestVariables
  };
};
