/*
 * Copyright (c) 2018, FusionAuth, All Rights Reserved
 */
'use strict';

var FusionAuth = FusionAuth || {};
FusionAuth.Admin = FusionAuth.Admin || {};

/**
 * Handles the JWT Configuration form - this should work on the Application and the System Configuration pages.
 *
 * @constructor
 */
FusionAuth.Admin.JWTConfiguration = function(element) {
  Prime.Utils.bindAll(this);

  this.element = element;
  this.algorithmSelect = element.queryFirst('select[name$=".jwtConfiguration.algorithm"]').addEventListener('change', this._handleJWTAlgorithmChange);
  this.settingsContainer = element.queryFirst('[data-jwt-settings-body]');
  this.generateTextContainer = element.queryFirst('[data-jwt-generate-text]');
  this.generateContainer = element.queryFirst('[data-jwt-generate-settings]');
  this.generateButton = this.generateContainer.queryFirst('a').addEventListener('click', this._handleGeneratorClick);

  this.rsaKeyLengthSelectContainer = element.queryFirst('[data-jwt-generate-settings] .select');
  this.rsaKeyLengthSelect = this.rsaKeyLengthSelectContainer.queryFirst('select');
  this.rsaContainer = element.queryFirst('[data-jwt-rsa]');
  this.rsaPrivateKeyEditor = new FusionAuth.UI.TextEditor(element.queryFirst('textarea[name$=".jwtConfiguration.privateKey"]'))
      .withOptions({'mode': 'text/plain', 'lineWrapping': true});
  this.rsaPublicKeyEditor = new FusionAuth.UI.TextEditor(element.queryFirst('textarea[name$=".jwtConfiguration.publicKey"]'))
      .withOptions({'mode': 'text/plain', 'lineWrapping': true});
  this.rsaPubliKeyInfoContainer = element.queryFirst('[data-jwt-rsa-public-key-info]');
  this.rsaPublicKeyInfoSpinner = element.queryFirst('[data-jwt-rsa-public-key-spinner]');
  this.rsaPrivateKeyInfoContainer = element.queryFirst('[data-jwt-rsa-private-key-info]');
  this.rsaPrivateKeyInfoSpinner = element.queryFirst('[data-jwt-rsa-private-key-spinner]');
  this.rsaVerifyKeysButton = this.rsaContainer.queryFirst('a').addEventListener('click', this._handleVerifyKeysClick);

  this.hmacContainer = element.queryFirst('[data-jwt-hmac]');
  this.hmacSecretEditor = new FusionAuth.UI.TextEditor(element.queryFirst('textarea[name$=".jwtConfiguration.secret"]'))
      .withOptions({'mode': 'text/plain', 'lineWrapping': true});

  // Applications can toggle this on and off, System Configuration may not, it is always enabled.
  this.enabledCheckbox = element.queryFirst('input[type="checkbox"][name$=".jwtConfiguration.enabled"]');
  if (this.enabledCheckbox !== null) {
    this.enabledCheckbox.addEventListener('change', this._handleEnabledClick);
  }
};

FusionAuth.Admin.JWTConfiguration.constructor = FusionAuth.Admin.JWTConfiguration;
FusionAuth.Admin.JWTConfiguration.prototype = {
  onTabShown: function() {
    // If we're on the application page and JWT Configuration is enabled, no need to continue.
    if (this.enabledCheckbox !== null && !this.enabledCheckbox.isChecked()) {
      this.toggleJWTSettingsBody();
      return;
    }

    var algorithm = this.algorithmSelect.getValue();
    if (algorithm.indexOf("RS") === 0) {
      this.rsaPrivateKeyEditor.render();
      this.rsaPublicKeyEditor.render();
    } else if (algorithm.indexOf("HS") === 0) {
      this.hmacSecretEditor.render();
    }

    this._handleJWTAlgorithmChange();
  },

  refreshKeyInfo: function() {
    this.rsaPublicKeyInfoSpinner.removeClass('fa-check fa-close blue-text green-text red-text').addClass('blue-text fa-refresh fa-spin');
    this.rsaPrivateKeyInfoSpinner.removeClass('fa-check fa-close blue-text green-text red-text').addClass('blue-text fa-refresh fa-spin');

    this.rsaPublicKeyEditor.sync();
    this.rsaPrivateKeyEditor.sync();

    var inProgress = new Prime.Widgets.InProgress(this.element.queryUp('.panel')).withMinimumTime(500);
    new Prime.Ajax.Request("/ajax/jwt/key-info", 'POST')
        .withData({'publicKey': this.rsaPublicKeyEditor.element.getValue(), 'privateKey': this.rsaPrivateKeyEditor.element.getValue()})
        .withInProgress(inProgress)
        .withSuccessHandler(this._handleKeyInfoSuccess)
        .withErrorHandler(this._handleKeyInfoError)
        .go();
  },

  toggleJWTSettingsBody: function() {
    if (this.enabledCheckbox.isChecked()) {
      //setTimeout(this._handleJWTAlgorithmChange, 500);
      this._handleJWTAlgorithmChange();
    }
  },

  /* ===================================================================================================================
   * Private methods
   * ===================================================================================================================*/

  _handleGeneratorClick: function(event) {
    Prime.Utils.stopEvent(event);

    this.generateButton.queryFirst('i').removeClass('fa-arrow-circle-right').addClass('fa-refresh fa-spin');
    this.rsaPublicKeyInfoSpinner.removeClass('fa-check fa-close blue-text green-text red-text').addClass('green-text fa-refresh fa-spin');
    this.rsaPrivateKeyInfoSpinner.removeClass('fa-check fa-close blue-text green-text red-text').addClass('green-text fa-refresh fa-spin');

    var algorithm = this.algorithmSelect.getValue();
    var keyLength = this.rsaKeyLengthSelect.getValue();

    if (algorithm === "none") {
      return;
    }

    var panel = this.element.queryUp('.panel');
    var inProgress = new Prime.Widgets.InProgress(panel).withMinimumTime(500);
    new Prime.Ajax.Request('/ajax/jwt/key-gen', 'GET')
        .withData({'algorithm': algorithm, 'keyLength': keyLength})
        .withInProgress(inProgress)
        .withSuccessHandler(this._handleKeyGenSuccess)
        .withErrorHandler(this._handleKeyGenError)
        .go();
  },

  _handleKeyGenError: function() {
    this.generateButton.queryFirst('i').removeClass('fa-refresh fa-spin').addClass('fa-arrow-circle-right');
    this.refreshKeyInfo();
  },

  _handleKeyGenSuccess: function(xhr) {
    var response = JSON.parse(xhr.responseText);
    if (response.privateKey) {
      this.rsaPrivateKeyEditor.setValue(response.privateKey);
    }

    if (response.publicKey) {
      this.rsaPublicKeyEditor.setValue(response.publicKey);
    }

    if (response.secret) {
      this.hmacSecretEditor.setValue(response.secret);
    }

    this.generateButton.queryFirst('i').removeClass('fa-refresh fa-spin').addClass('fa-arrow-circle-right');
    this.refreshKeyInfo();
  },

  _handleKeyInfoError: function() {
    this.rsaPubliKeyInfoContainer.setHTML('Key format: unknown Key Length: unknown');
    this.rsaPublicKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-close red-text');
    this.rsaPrivateKeyInfoContainer.setHTML('Key format: unknown Key Length: unknown');
    this.rsaPrivateKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-close red-text');
  },

  _handleKeyInfoSuccess: function(xhr) {
    var response = JSON.parse(xhr.responseText);

    if (response.publicKeyFormat === "invalid" || !Prime.Utils.isDefined(response.publicKeyFormat)) {
      this.rsaPublicKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-close red-text');
    } else {
      this.rsaPublicKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-check green-text');
    }

    if (response.privateKeyFormat === "invalid" || !Prime.Utils.isDefined(response.privateKeyFormat)) {
      this.rsaPrivateKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-close red-text');
    } else {
      this.rsaPrivateKeyInfoSpinner.removeClass('fa-check fa-refresh fa-spin red-text green-text').addClass('fa-check green-text');
    }

    this.rsaPubliKeyInfoContainer.setHTML('Key format: ' + response.publicKeyFormat + ' Key Length: ' + response.publicKeyLength);
    this.rsaPrivateKeyInfoContainer.setHTML('Key format: ' + response.privateKeyFormat + ' Key Length: ' + response.privateKeyLength);

    // Set the generate key length to the same length as the current key
    if (Prime.Utils.isDefined(response.privateKeyLength)) {
      this.rsaKeyLengthSelect.setValue(response.privateKeyLength);
    }
  },

  _handleJWTAlgorithmChange: function() {
    var algorithm = this.algorithmSelect.getValue();

    if (algorithm.indexOf("HS") === 0) {
      this.generateTextContainer.setHTML(this.generateTextContainer.getDataAttribute('jwtHmacText'));
      this.generateContainer.show();
      this.rsaKeyLengthSelectContainer.hide();

      this.rsaContainer.hide();
      this.hmacContainer.show();
      this.hmacSecretEditor.render().setHeight(75);
    } else if (algorithm.indexOf("RS") === 0) {
      this.generateTextContainer.setHTML(this.generateTextContainer.getDataAttribute('jwtRsaText'));
      this.generateContainer.show();
      this.rsaKeyLengthSelectContainer.show();

      this.rsaContainer.show();
      this.hmacContainer.hide();
      this.rsaPublicKeyEditor.render();
      this.rsaPrivateKeyEditor.render();
      this.refreshKeyInfo();
    } else {
      this.generateContainer.hide();
      this.rsaContainer.hide();
      this.hmacContainer.hide();
    }
  },

  _handleEnabledClick: function() {
    this.toggleJWTSettingsBody();
  },

  _handleVerifyKeysClick: function(event) {
    Prime.Utils.stopEvent(event);
    this.refreshKeyInfo();
  }
};