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

import { currentRouteName, currentURL, settled } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { v4 as uuidv4 } from 'uuid';

import { create } from 'ember-cli-page-object';
import page from 'vault/tests/pages/settings/mount-secret-backend';
import configPage from 'vault/tests/pages/secrets/backend/configuration';
import authPage from 'vault/tests/pages/auth';
import consoleClass from 'vault/tests/pages/components/console/ui-panel';
import logout from 'vault/tests/pages/logout';
import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend';
import { allEngines } from 'vault/helpers/mountable-secret-engines';

const consoleComponent = create(consoleClass);

module('Acceptance | settings/mount-secret-backend', function (hooks) {
  setupApplicationTest(hooks);

  hooks.beforeEach(function () {
    this.uid = uuidv4();
    return authPage.login();
  });

  test('it sets the ttl correctly when mounting', async function (assert) {
    // always force the new mount to the top of the list
    const path = `mount-kv-${this.uid}`;
    const defaultTTLHours = 100;
    const maxTTLHours = 300;

    await page.visit();

    assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
    await page.selectType('kv');
    await page
      .next()
      .path(path)
      .toggleOptions()
      .enableDefaultTtl()
      .defaultTTLUnit('h')
      .defaultTTLVal(defaultTTLHours)
      .enableMaxTtl()
      .maxTTLUnit('h')
      .maxTTLVal(maxTTLHours)
      .submit();
    await configPage.visit({ backend: path });
    assert.strictEqual(configPage.defaultTTL, `${defaultTTLHours}h`, 'shows the proper TTL');
    assert.strictEqual(configPage.maxTTL, `${maxTTLHours}h`, 'shows the proper max TTL');
  });

  test('it sets the ttl when enabled then disabled', async function (assert) {
    // always force the new mount to the top of the list
    const path = `mount-kv-${this.uid}`;
    const maxTTLHours = 300;

    await page.visit();

    assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
    await page.selectType('kv');
    await page
      .next()
      .path(path)
      .toggleOptions()
      .enableDefaultTtl()
      .enableDefaultTtl()
      .enableMaxTtl()
      .maxTTLUnit('h')
      .maxTTLVal(maxTTLHours)
      .submit();
    await configPage.visit({ backend: path });
    assert.strictEqual(configPage.defaultTTL, '0s', 'shows the proper TTL');
    assert.strictEqual(configPage.maxTTL, `${maxTTLHours}h`, 'shows the proper max TTL');
  });

  test('it sets the max ttl after pki chosen, resets after', async function (assert) {
    await page.visit();
    assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
    await page.selectType('pki');
    await page.next();
    assert.dom('[data-test-input="maxLeaseTtl"]').exists();
    assert
      .dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]')
      .isChecked('Toggle is checked by default');
    assert.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-value]').hasValue('3650');
    assert.dom('[data-test-input="maxLeaseTtl"] [data-test-select="ttl-unit"]').hasValue('d');

    // Go back and choose a different type
    await page.back();
    await page.selectType('database');
    await page.next();
    assert.dom('[data-test-input="maxLeaseTtl"]').exists('3650');
    assert
      .dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]')
      .isNotChecked('Toggle is unchecked by default');
    await page.enableMaxTtl();
    assert.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-value]').hasValue('');
    assert.dom('[data-test-input="maxLeaseTtl"] [data-test-select="ttl-unit"]').hasValue('s');
  });

  test('it throws error if setting duplicate path name', async function (assert) {
    const path = `kv-duplicate`;

    await consoleComponent.runCommands([
      // delete any kv-duplicate previously written here so that tests can be re-run
      `delete sys/mounts/${path}`,
    ]);

    await page.visit();

    assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
    await page.selectType('kv');
    await page.next().path(path).submit();
    await page.secretList();
    await settled();
    await page.enableEngine();
    await page.selectType('kv');
    await page.next().path(path).submit();
    assert.dom('[data-test-alert-banner="alert"]').containsText(`path is already in use at ${path}`);
    assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');

    await page.secretList();
    await settled();
    assert
      .dom(`[data-test-auth-backend-link=${path}]`)
      .exists({ count: 1 }, 'renders only one instance of the engine');
  });

  test('version 2 with no update to config endpoint still allows mount of secret engine', async function (assert) {
    const enginePath = `kv-noUpdate-${this.uid}`;
    const V2_POLICY = `
      path "${enginePath}/*" {
        capabilities = ["list","create","read","sudo","delete"]
      }
      path "sys/mounts/*"
      {
        capabilities = ["create", "read", "update", "delete", "list", "sudo"]
      }

      # List existing secrets engines.
      path "sys/mounts"
      {
        capabilities = ["read"]
      }
      # Allow page to load after mount
      path "sys/internal/ui/mounts/${enginePath}" {
        capabilities = ["read"]
      }
    `;
    await consoleComponent.runCommands([
      // delete any previous mount with same name
      `delete sys/mounts/${enginePath}`,
      `write sys/policies/acl/kv-v2-degrade policy=${btoa(V2_POLICY)}`,
      'write -field=client_token auth/token/create policies=kv-v2-degrade',
    ]);
    await settled();
    const userToken = consoleComponent.lastLogOutput;
    await logout.visit();
    await authPage.login(userToken);
    // create the engine
    await mountSecrets.visit();
    await mountSecrets.selectType('kv');
    await mountSecrets.next().path(enginePath).setMaxVersion(101).submit();
    await settled();
    assert
      .dom('[data-test-flash-message]')
      .containsText(
        `You do not have access to the config endpoint. The secret engine was mounted, but the configuration settings were not saved.`
      );
    assert.strictEqual(
      currentURL(),
      `/vault/secrets/${enginePath}/list`,
      'After mounting, redirects to secrets list page'
    );
    await configPage.visit({ backend: enginePath });
    await settled();
    assert.dom('[data-test-row-value="Maximum number of versions"]').hasText('Not set');
  });

  test('it should transition to engine route on success if defined in mount config', async function (assert) {
    await consoleComponent.runCommands([
      // delete any previous mount with same name
      `delete sys/mounts/kubernetes`,
    ]);
    await mountSecrets.visit();
    await mountSecrets.selectType('kubernetes');
    await mountSecrets.next().path('kubernetes').submit();
    const { engineRoute } = allEngines().findBy('type', 'kubernetes');
    assert.strictEqual(
      currentRouteName(),
      `vault.cluster.secrets.backend.${engineRoute}`,
      'Transitions to engine route on mount success'
    );
  });
});
