var assert = require('chai').assert;
let LMLayer = require('../../build/headless');

/*
 * How to run the worlist
 */
describe('LMLayer using the trie model', function () {
  describe('Prediction', function () {
    var EXPECTED_SUGGESTIONS = 3;
    it('will predict an empty buffer', function () {
      var lmLayer = new LMLayer(capabilities());

      // We're testing many as asynchronous messages in a row.
      // this would be cleaner using async/await syntax.
      // Not done yet, as this test case is a slightly-edited copy of the in-browser version.
      return lmLayer.loadModel(
        // We're running headlessly, so the path can be relative to the npm root directory.
        "unit_tests/in_browser/resources/models/simple-trie.js"
      ).then(function (_actualConfiguration) {
        return Promise.resolve();
      }).then(function () {
        return lmLayer.predict(zeroTransform(), atEndOfBuffer(''));
      }).then(function (suggestions) {
        // TODO: not super sure what to assert here!
        assert.isAtLeast(suggestions.length, EXPECTED_SUGGESTIONS);
        return lmLayer.predict(type('t'), atEndOfBuffer(''));
      }).then(function (suggestions) {
        assert.isAtLeast(suggestions.length, EXPECTED_SUGGESTIONS);
        return lmLayer.predict(type('h'), atEndOfBuffer('t'));
      }).then(function (suggestions) {
        assert.isAtLeast(suggestions.length, EXPECTED_SUGGESTIONS);
        return lmLayer.predict(type('q'), atEndOfBuffer('the '));
      }).then(function (suggestions) {
        assert.isAtLeast(suggestions.length, EXPECTED_SUGGESTIONS);
        lmLayer.shutdown();
        return Promise.resolve();
      });
    });
  });

  describe('Regression tests', function () {
    // Building the model with the default searchTermToKey implementation
    // should also use the default implementation in the frontend.
    //
    // I've compiled a model with the defaults for the word 'naïve', and its
    // search key is 'naive' accordingly (default searchTermToKey transforms
    // to NFD and removes common diacritics).
    //
    // The lookup should also do the same to the input!
    //
    // https://community.software.sil.org/t/search-term-to-key-in-lexical-model-not-working-both-ways-by-default/3133
    it('should use the default searchTermToKey()', function () {
      var lmLayer = new LMLayer(capabilities());

      return lmLayer.loadModel(
        // We're running headlessly, so the path can be relative to the npm root directory.
        "unit_tests/in_browser/resources/models/naive-trie.js"
      ).then(function (_actualConfiguration) {
        return Promise.resolve();
      }).then(function () {
        // Pretend we are typing 'na|ï'
        // Notice that we are typing the diacritic!
        return lmLayer.predict(type('ï'), atEndOfBuffer('na'));
      }).then(function (rawSuggestions) {
        // Discard the keep suggestion
        var suggestions = rawSuggestions.filter(function skimKeepSuggestions(s) {
          return s.tag !== 'keep'
        })
        assert.isAtLeast(suggestions.length, 1)

        // We SHOULD get 'naïve' suggested
        var topSuggestion = suggestions[0];
        assert.equal(topSuggestion.displayAs, "naïve")
        assert.include(topSuggestion.transform.insert, "ïve")
      });
    });
  });

  /**
   * Type some text (as a transform).
   * @param  {string} text to type
   * @return {Transform}
   */
  function type(text)  {
    return { insert: text, deleteLeft: 0 };
  }

  /**
   * Create a context at the end of the buffer with the given text.
   * @param {string} buffer
   * @return {Context}
   */
  function atEndOfBuffer(buffer) {
    return { left: buffer, startOfBuffer: buffer.length === 0, endOfBuffer: true }
  }

  function zeroTransform() {
    return { insert: '', deleteLeft: 0 };
  }
});
