import * as tools from '@eui/tools/scripts/utils/tools.js';
import path from 'path';
import VaultService from '@eui/automation/core/services/vault-service.js';

(async function () {

  // Editable defaults. You can change these values and run the script directly.
  const defaultConfig = {
    // Use either token OR user/password. namespace is optional.
    source: {
      vaultConfig: {
        // endpoint: '<ENDTPOINT>',
        // token: '<DST_TOKEN>',
        // user: '<DST_USER>',
        // password: '<DST_PASSWORD>',
        version: 'v1'
      }
    },
    target: {
      vaultConfig: {
        // endpoint: '<ENDTPOINT>',
        // token: '<DST_TOKEN>',
        // user: '<DST_USER>',
        // password: '<DST_PASSWORD>',
        version: 'v2'
      }
    },
    concurrency: 5,
    // Configure mount mapping below if reading from one mount and writing to another.
    mountMapping: {
      fromMount: 'oldSecretsEngine',
      toMount: 'newSecretsEngine'
    }
  };

  const sourceConfig = defaultConfig.source;
  const targetConfig = defaultConfig.target;
  const effectiveConcurrency = parseInt(defaultConfig.concurrency, 10);

  // Derive base path from mount mapping (migrate entire mount)
  const effectiveBasePath = '/' + (defaultConfig.mountMapping.fromMount || 'secret');

  if (!sourceConfig || !sourceConfig.vaultConfig) throw new Error('Invalid source config');
  if (!targetConfig || !targetConfig.vaultConfig) throw new Error('Invalid target config');

  const sourceVs = new VaultService({ vaultConfig: { ...sourceConfig.vaultConfig, version: 'v1' } });
  const targetVs = new VaultService({ vaultConfig: { ...targetConfig.vaultConfig, version: 'v2' } });

  tools.logTitle('Vault v1 → v2 migration');
  tools.logInfo('Listing top-level keys under ' + effectiveBasePath);
  const keys = await sourceVs.listKeys(effectiveBasePath);
  tools.logInfo('Found ' + keys.length + ' items');

  // Determine mount mapping (write to new mount if provided)
  function getMountFromPath(p) {
    if (!p.startsWith('/')) return null;
    const idx = p.indexOf('/', 1);
    return idx > -1 ? p.slice(1, idx) : p.slice(1);
  }
  function replaceMount(prefix, fromMount, toMount) {
    if (!fromMount || !toMount || fromMount === toMount) return prefix;
    const hasLeading = prefix.startsWith('/');
    const clean = hasLeading ? prefix.slice(1) : prefix;
    const idx = clean.indexOf('/');
    const mount = idx === -1 ? clean : clean.slice(0, idx);
    if (mount !== fromMount) return prefix;
    const rest = idx === -1 ? '' : clean.slice(idx);
    return '/' + toMount + rest;
  }
  const inferredOldMount = getMountFromPath(effectiveBasePath);
  const mappingConf = defaultConfig.mountMapping || {};
  const writeOldMount = mappingConf.fromMount || inferredOldMount;
  const writeNewMount = mappingConf.toMount || writeOldMount;

  async function processKey(prefix, key) {
    if (key.endsWith('/')) {
      const subBase = path.posix.join(prefix, key);
      const subKeys = await sourceVs.listKeys(subBase);
      for (const subKey of subKeys) {
        await processKey(subBase, subKey);
      }
    } else {
      const secret = await sourceVs.getSecret(prefix, key);
      const payload = secret[key];
      if (payload && typeof payload === 'object') {
        const writePrefix = replaceMount(prefix, writeOldMount, writeNewMount);
        await targetVs.createUpdateSecret(writePrefix, key, payload);
        tools.logInfo('Migrated ' + path.posix.join(prefix, key));
      } else {
        tools.logWarn('Skipping non-object payload at ' + path.posix.join(prefix, key));
      }
    }
  }

  let idx = 0;
  const conc = effectiveConcurrency;
  async function nextBatch() {
    const batch = [];
    while (idx < keys.length && batch.length < conc) {
      batch.push(processKey(effectiveBasePath, keys[idx++]));
    }
    if (batch.length > 0) {
      await Promise.all(batch);
      await nextBatch();
    }
  }

  await nextBatch();
  tools.logTitle('Migration completed');

  // Policy augmentation removed by request; users/groups/policies stay unchanged.

})().catch(err => {
  console.error('Migration failed:', err.message);
  if (err.stack) console.error(err.stack);
  process.exit(1);
});


