/**
 * Copyright IBM Corp. 2016, 2025
 * SPDX-License-Identifier: BUSL-1.1
 */

// 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 Service from '@ember/service';
import { getOwner } from '@ember/owner';
import { shiftCommandIndex } from 'vault/lib/console-helpers';
import { encodePath } from 'vault/utils/path-encoding-helpers';
import { sanitizePath, ensureTrailingSlash } from 'core/utils/sanitize-path';
import { tracked } from '@glimmer/tracking';
import { addManyToArray } from 'vault/helpers/add-to-array';

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

export default class ConsoleService extends Service {
  @tracked isOpen = false;
  @tracked commandIndex = null;
  @tracked log = [];

  get commandHistory() {
    return this.log.filter((log) => log.type === 'command');
  }

  // Not a getter so it can be stubbed in tests
  adapter() {
    return getOwner(this).lookup('adapter:console');
  }

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

  clearLog(clearAll = false) {
    let history;
    if (!clearAll) {
      history = this.commandHistory.slice();
      history.setEach('hidden', true);
    }
    this.log = [];
    if (history) {
      this.log = addManyToArray(this.log, history);
    }
  }

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

  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,
    });
  }
}
