/**
 * Copyright (c) HashiCorp, Inc.
 * SPDX-License-Identifier: MPL-2.0
 */

// Low level service that allows users to input paths to make requests to vault
// this service provides the UI synecdote to the cli commands read, write, delete, and list
import { filterBy } from '@ember/object/computed';

import Service from '@ember/service';

import { getOwner } from '@ember/application';
import { computed } from '@ember/object';
import { shiftCommandIndex } from 'vault/lib/console-helpers';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export function sanitizePath(path) {
  //remove whitespace + remove trailing and leading slashes
  return path.trim().replace(/^\/+|\/+$/g, '');
}
export function ensureTrailingSlash(path) {
  return path.replace(/(\w+[^/]$)/g, '$1/');
}

const VERBS = {
  read: 'GET',
  list: 'GET',
  write: 'POST',
  delete: 'DELETE',
};

export default Service.extend({
  isOpen: false,

  adapter() {
    return getOwner(this).lookup('adapter:console');
  },
  commandHistory: filterBy('log', 'type', 'command'),
  log: computed(function () {
    return [];
  }),
  commandIndex: null,

  shiftCommandIndex(keyCode, setCommandFn = () => {}) {
    const [newIndex, newCommand] = shiftCommandIndex(keyCode, this.commandHistory, this.commandIndex);
    if (newCommand !== undefined && newIndex !== undefined) {
      this.set('commandIndex', newIndex);
      setCommandFn(newCommand);
    }
  },

  clearLog(clearAll = false) {
    const log = this.log;
    let history;
    if (!clearAll) {
      history = this.commandHistory.slice();
      history.setEach('hidden', true);
    }
    log.clear();
    if (history) {
      log.addObjects(history);
    }
  },

  logAndOutput(command, logContent) {
    const log = this.log;
    if (command) {
      log.pushObject({ type: 'command', content: command });
      this.set('commandIndex', null);
    }
    if (logContent) {
      log.pushObject(logContent);
    }
  },

  ajax(operation, path, options = {}) {
    const verb = VERBS[operation];
    const adapter = this.adapter();
    const url = adapter.buildURL(encodePath(path));
    const { data, wrapTTL } = options;
    return adapter.ajax(url, verb, {
      data,
      wrapTTL,
    });
  },

  kvGet(path, data, flags = {}) {
    const { wrapTTL, metadata } = flags;
    // Split on first / to find backend and secret path
    const pathSegment = metadata ? 'metadata' : 'data';
    const [backend, secretPath] = path.split(/\/(.+)?/);
    const kvPath = `${backend}/${pathSegment}/${secretPath}`;
    return this.ajax('read', sanitizePath(kvPath), { wrapTTL });
  },

  read(path, data, flags) {
    const wrapTTL = flags?.wrapTTL;
    return this.ajax('read', sanitizePath(path), { wrapTTL });
  },

  write(path, data, flags) {
    const wrapTTL = flags?.wrapTTL;
    return this.ajax('write', sanitizePath(path), { data, wrapTTL });
  },

  delete(path) {
    return this.ajax('delete', sanitizePath(path));
  },

  list(path, data, flags) {
    const wrapTTL = flags?.wrapTTL;
    const listPath = ensureTrailingSlash(sanitizePath(path));
    return this.ajax('list', listPath, {
      data: {
        list: true,
      },
      wrapTTL,
    });
  },
});
