/**
 * Copyright IBM Corp. 2016, 2025
 * SPDX-License-Identifier: BUSL-1.1
 */
import Model, { attr } from '@ember-data/model';
import { service } from '@ember/service';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { getRoleFields } from 'vault/utils/model-helpers/database-helpers';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import { withModelValidations } from 'vault/decorators/model-validations';
const validations = {
  name: [{ type: 'presence', message: 'Role name is required.' }],
  database: [{ type: 'presence', message: 'Database is required.' }],
  type: [{ type: 'presence', message: 'Type is required.' }],
  username: [
    {
      validator(model) {
        const { type, username } = model;
        if (!type || type === 'dynamic') return true;
        if (username) return true;
      },
      message: 'Username is required.',
    },
  ],
};
@withModelValidations(validations)
export default class RoleModel extends Model {
  @service version;

  idPrefix = 'role/';

  @attr('string', { readOnly: true }) backend;

  @attr('string', { label: 'Role name' }) name;

  @attr('array', {
    label: 'Connection name',
    editType: 'searchSelect',
    fallbackComponent: 'string-list',
    models: ['database/connection'],
    selectLimit: 1,
    onlyAllowExisting: true,
    subText: 'The database connection for which credentials will be generated.',
  })
  database;

  @attr('string', {
    label: 'Type of role',
    noDefault: true,
    possibleValues: ['static', 'dynamic'],
  })
  type;

  @attr({
    editType: 'ttl',
    defaultValue: '1h',
    label: 'Generated credentials’s Time-to-Live (TTL)',
    helperTextDisabled: 'Vault will use a TTL of 1 hour.',
    defaultShown: 'Engine default',
  })
  default_ttl;

  @attr({
    editType: 'ttl',
    defaultValue: '24h',
    label: 'Generated credentials’s maximum Time-to-Live (Max TTL)',
    helperTextDisabled: 'Vault will use a TTL of 24 hours.',
    defaultShown: 'Engine default',
  })
  max_ttl;

  @attr('string', { subText: 'The database username that this Vault role corresponds to.' }) username;

  @attr({
    editType: 'ttl',
    defaultValue: '24h',
    helperTextDisabled:
      'Specifies the amount of time Vault should wait before rotating the password. The minimum is 5 seconds. Default is 24 hours.',
    helperTextEnabled: 'Vault will rotate password after.',
  })
  rotation_period;

  @attr('array', {
    editType: 'stringArray',
  })
  creation_statements;

  @attr('array', {
    editType: 'stringArray',
    defaultShown: 'Default',
  })
  revocation_statements;

  @attr('array', {
    editType: 'stringArray',
    defaultShown: 'Default',
  })
  rotation_statements;

  @attr('array', {
    editType: 'stringArray',
    defaultShown: 'Default',
  })
  rollback_statements;

  @attr('array', {
    editType: 'stringArray',
    defaultShown: 'Default',
  })
  renew_statements;

  @attr('string', {
    editType: 'json',
    allowReset: true,
    theme: 'hashi short',
    defaultShown: 'Default',
  })
  creation_statement;

  @attr('string', {
    editType: 'json',
    allowReset: true,
    theme: 'hashi short',
    defaultShown: 'Default',
  })
  revocation_statement;

  @attr('string', { readOnly: true }) last_vault_rotation;

  // ENTERPRISE ONLY
  @attr({
    label: 'Rotate immediately',
    editType: 'toggleButton',
    helperTextEnabled: 'Vault will rotate the password for this static role on creation.',
    helperTextDisabled: "Vault will not rotate this role's password on creation.",
    isOppositeValue: true,
  })
  skip_import_rotation;

  @attr('string', {
    sensitive: true,
    subText: 'The database password that this Vault role corresponds to.',
  })
  password;

  /* FIELD ATTRIBUTES */
  get fieldAttrs() {
    // Main fields on edit/create form
    const fields = ['name', 'database', 'type'];
    return expandAttributeMeta(this, fields);
  }
  get showFields() {
    let fields = ['name', 'database', 'type'];
    fields = fields.concat(getRoleFields(this.type)).concat(['creation_statements']);
    // elasticsearch does not support revocation statements: https://developer.hashicorp.com/vault/api-docs/secret/databases/elasticdb#parameters-1
    if (this.database[0] !== 'elasticsearch') {
      fields = fields.concat(['revocation_statements']);
    }
    return expandAttributeMeta(this, fields);
  }
  get roleSettingAttrs() {
    // logic for which get displayed is on DatabaseRoleSettingForm
    let allRoleSettingFields = [
      'default_ttl',
      'max_ttl',
      'username',
      'password',
      'rotation_period',
      'skip_import_rotation',
      'creation_statements',
      'creation_statement', // for editType: JSON
      'revocation_statements',
      'revocation_statement', // only for MongoDB (editType: JSON)
      'rotation_statements',
      'rollback_statements',
      'renew_statements',
    ];

    // remove enterprise-only attrs if on community
    if (!this.version.isEnterprise) {
      allRoleSettingFields = allRoleSettingFields.filter(
        (role) => !['skip_import_rotation', 'password'].includes(role)
      );
    }

    return expandAttributeMeta(this, allRoleSettingFields);
  }
  /* CAPABILITIES */
  // only used for secretPath
  @attr('string', { readOnly: true }) path;
  @lazyCapabilities(apiPath`${'backend'}/${'path'}/${'id'}`, 'backend', 'path', 'id') secretPath;
  @lazyCapabilities(apiPath`${'backend'}/roles/+`, 'backend') dynamicPath;
  @lazyCapabilities(apiPath`${'backend'}/static-roles/+`, 'backend') staticPath;
  @lazyCapabilities(apiPath`${'backend'}/creds/${'id'}`, 'backend', 'id') credentialPath;
  @lazyCapabilities(apiPath`${'backend'}/static-creds/${'id'}`, 'backend', 'id') staticCredentialPath;
  @lazyCapabilities(apiPath`${'backend'}/config/${'database[0]'}`, 'backend', 'database') databasePath;
  @lazyCapabilities(apiPath`${'backend'}/rotate-role/${'id'}`, 'backend', 'id') rotateRolePath;

  get canEditRole() {
    return this.secretPath.get('canUpdate');
  }
  get canDelete() {
    return this.secretPath.get('canDelete');
  }
  get canCreateDynamic() {
    return this.dynamicPath.get('canCreate');
  }
  get canCreateStatic() {
    return this.staticPath.get('canCreate');
  }
  get canGenerateCredentials() {
    return this.credentialPath.get('canRead');
  }
  get canGetCredentials() {
    return this.staticCredentialPath.get('canRead');
  }
  get canUpdateDb() {
    return this.databasePath.get('canUpdate');
  }
  get canRotateRoleCredentials() {
    return this.rotateRolePath.get('canUpdate');
  }
}
