text: const { NotImplementedError } = require('../extensions/index.js');
  
  /**
   * Implement class VigenereCipheringMachine that allows us to create
   * direct and reverse ciphering machines according to task description
   *
   * @example
   *
   * const directMachine = new VigenereCipheringMachine();
   *
   * const reverseMachine = new VigenereCipheringMachine(false);
   *
   * directMachine.encrypt('attack at dawn!', 'alphonse') => 'AEIHQX SX DLLU!'
   *
   * directMachine.decrypt('AEIHQX SX DLLU!', 'alphonse') => 'ATTACK AT DAWN!'
   *
   * reverseMachine.encrypt('attack at dawn!', 'alphonse') => '!ULLD XS XQHIEA'
   *
   * reverseMachine.decrypt('AEIHQX SX DLLU!', 'alphonse') => '!NWAD TA KCATTA'
   *
   */
  class VigenereCipheringMachine {
    // Explanation: https://www.youtube.com/watch?v=KST4bGAH-8Y
  
    constructor(isDirect = true) {
      this.isDirect = isDirect;
      this.alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    }
  
    encrypt(message, key) {
      this.validateParams(message, key);
  
      return this.process(message, key);
    }
  
    decrypt(message, key) {
      this.validateParams(message, key);
  
      return this.process(message, key, false);
    }
  
    validateParams(message, key) {
      if (!message || !key) {
        throw Error('Incorrect arguments!');
      }
    }
  
    process(message, key, isEncrypt = true) {
      const messageChars = message.toLowerCase().split('');
      const keyChars = key.toLowerCase().split('');
      const result = messageChars.reduce(
        (acc, x) => {
          if (acc.keyCharIndex === keyChars.length) {
            acc.keyCharIndex = 0;
          }
  
          const messageCharIndex = this.alphabet.indexOf(x);
  
          // Skip processing if message char is not presented in alphabet.
          if (messageCharIndex === -1) {
            acc.processedString += x;
          } else {
            const keyCharIndexInAlphabet = this.alphabet.indexOf(keyChars[acc.keyCharIndex]);
            const index = isEncrypt ? keyCharIndexInAlphabet + messageCharIndex : (messageCharIndex - keyCharIndexInAlphabet) % this.alphabet.length;
            const processedCharIndex = isEncrypt ? (index > 0 ? index % this.alphabet.length : 0) : index > 0 ? index : (index + this.alphabet.length) % this.alphabet.length;
  
            acc.processedString += this.alphabet[processedCharIndex];
            acc.keyCharIndex++;
          }
  
          return acc;
        },
        {
          processedString: '',
          keyCharIndex: 0
        }
      ).processedString;
  
      return (this.isDirect ? result : result.split('').reverse().join('')).toUpperCase();
    }
  }
  
  module.exports = {
    VigenereCipheringMachine
  };
  