'use strict';
const _ = require('lodash');
const inquirer = require('inquirer');
const diff = require('diff');
const chalk = require('chalk');

const logger = require('./util/log');

class TerminalAdapter {
  /**
   * `TerminalAdapter` is the default implementation of `Adapter`, an abstraction
   * layer that defines the I/O interactions.
   *
   * It provides a CLI interaction
   *
   * @constructor
   * @param {Object}          [options]
   * @param {Console} [options.console]
   */
  constructor(options = {}) {
    const stdout = options.stdout || process.stdout;
    const stderr = options.stderr || options.stdout || process.stderr;
    this.promptModule = inquirer.createPromptModule({skipTTYChecks: true, input: options.stdin, output: stdout});
    this.console = options.console || new console.Console(stdout, stderr);

    this.log = logger({console: this.console, stdout: options.stdout});
  }

  get _colorDiffAdded() {
    return chalk.black.bgGreen;
  }

  get _colorDiffRemoved() {
    return chalk.bgRed;
  }

  _colorLines(name, str) {
    return str.split('\n').map(line => this[`_colorDiff${name}`](line)).join('\n');
  }

  /**
   * Prompt a user for one or more questions and pass
   * the answer(s) to the provided callback.
   *
   * It shares its interface with `Base.prompt`
   *
   * (Defined inside the constructor to keep interfaces separated between
   * instances)
   *
   * @param {Object|Object[]} questions
   * @param {Object} [answers] Answers to be passed to inquirer
   * @param {Function} [callback] callback
   */
  prompt(questions, answers, cb) {
    if (typeof answers === 'function') {
      cb = answers;
      answers = undefined;
    }
    const promise = this.promptModule(questions, answers);
    promise.then(cb || _.noop);
    return promise;
  }

  /**
   * Shows a color-based diff of two strings
   *
   * @param {string} actual
   * @param {string} expected
   * @param {Array} changes returned by diff.
   */
  diff(actual, expected, changes) {
    if (Array.isArray(actual)) {
      changes = actual;
    }
    changes = changes || diff.diffLines(actual, expected);
    let msg = changes.map(str => {
      if (str.added) {
        return this._colorLines('Added', str.value);
      }

      if (str.removed) {
        return this._colorLines('Removed', str.value);
      }

      return str.value;
    }).join('');

    // Legend
    msg = '\n' +
      this._colorDiffRemoved('removed') +
      ' ' +
      this._colorDiffAdded('added') +
      '\n\n' +
      msg +
      '\n';

    this.console.log(msg);
    return msg;
  }
}

module.exports = TerminalAdapter;