import EventEmitter from './events';
import defaultOptions from './defaultOptions';

const onStepsPrevious = Symbol('onStepsPrevious');
const onStepsNext = Symbol('onStepsNext');

export default class bulmaSteps extends EventEmitter {
  constructor(selector, options = {}) {
    super();

    this.element = typeof selector === 'string'
      ? document.querySelector(selector)
      : selector;
    // An invalid selector or non-DOM node has been provided.
    if (!this.element) {
      throw new Error('An invalid selector or non-DOM node has been provided.');
    }

    this._clickEvents = ['click'];
    /// Set default options and merge with instance defined
    this.options = {
      ...defaultOptions,
      ...options
    };

    this[onStepsPrevious] = this[onStepsPrevious].bind(this);
    this[onStepsNext] = this[onStepsNext].bind(this);

    this.init();
  }

  /**
   * Initiate all DOM element containing carousel class
   * @method
   * @return {Array} Array of all Carousel instances
   */
  static attach(selector = '.steps', options = {}) {
    let instances = new Array();

    const elements = document.querySelectorAll(selector);
    [].forEach.call(elements, element => {
      setTimeout(() => {
        instances.push(new bulmaSteps(element, options));
      }, 100);
    });
    return instances;
  }

  /**
   * Initiate plugin
   * @method init
   * @return {void}
   */
  init() {
    this._id = 'bulmaSteps' + (new Date()).getTime() + Math.floor(Math.random() * Math.floor(9999));

    this.steps = this.element.querySelectorAll(this.options.selector);
    this.contents = this.element.querySelectorAll(this.options.selector_content);
    this.previous_btn = this.element.querySelector(this.options.previous_selector);
    this.next_btn = this.element.querySelector(this.options.next_selector);

    [].forEach.call(this.steps, (step, index) => {
      step.setAttribute('data-step-id', index);
    });

    if (this.steps && this.steps.length) {
      this.activate_step(0);
      this.updateActions(this.steps[0]);
    }

    this._bindEvents();

    this.emit('bulmasteps:ready', this.element.value);
  }

  /**
   * Bind all events
   * @method _bindEvents
   * @return {void}
   */
  _bindEvents() {
    if (this.previous_btn != null) {
      this._clickEvents.forEach(event => {
        this.previous_btn.addEventListener(event, this[onStepsPrevious], false);
      });
    }

    if (this.next_btn != null) {
      this._clickEvents.forEach(event => {
        this.next_btn.addEventListener(event, this[onStepsNext], false);
      });
    }

    if (this.options.stepClickable) {
      [].forEach.call(this.steps, (step, index) => {
        this._clickEvents.forEach(event => {
          while(index > this.current_id) {
            this[onStepsNext](event);
          }
          while(index < this.current_id) {
            this[onStepsPrevious](event);
          }
        });
      })
    }
  }

  [onStepsPrevious](e) {
    e.preventDefault();

    if (!e.target.getAttribute('disabled')) {
      this.previous_step();
    }
  }

  [onStepsNext](e) {
    e.preventDefault();

    if (!e.target.getAttribute('disabled')) {
      this.next_step();
    }
  }

  get_current_step_id() {
    for (var i = 0; i < this.steps.length; i++) {
      var step = this.steps[i];

      if (step.classList.contains(this.options.active_class)) {
        return parseInt(step.getAttribute('data-step-id'));
      }
    }

    return null;
  }

  updateActions(step) {
    var stepId = parseInt(step.getAttribute('data-step-id'));
    if (stepId == 0) {
      if (this.previous_btn != null) {
        this.previous_btn.setAttribute('disabled', 'disabled');
      }
      if (this.next_btn != null) {
        this.next_btn.removeAttribute('disabled', 'disabled');
      }
    } else if (stepId == (this.steps.length - 1)) {
      if (this.previous_btn != null) {
        this.previous_btn.removeAttribute('disabled', 'disabled');
      }
      if (this.next_btn != null) {
        this.next_btn.setAttribute('disabled', 'disabled');
      }
    } else {
      if (this.previous_btn != null) {
        this.previous_btn.removeAttribute('disabled', 'disabled');
      }
      if (this.next_btn != null) {
        this.next_btn.removeAttribute('disabled', 'disabled');
      }
    }
  }

  async next_step() {
    var current_id = this.get_current_step_id();

    if (current_id == null) {
      return;
    }

    var next_id = current_id + 1,
      errors = [];

    if (typeof this.options.beforeNext != 'undefined' && this.options.beforeNext != null && this.options.beforeNext) {
      errors = await this.options.beforeNext(current_id);
    }
    this.emit('bulmasteps:before:next', current_id);

    if (typeof errors == 'undefined') {
      errors = [];
    }

    if (errors.length > 0) {
      this.emit('bulmasteps:errors', errors);
      for (var i = 0; i < errors.length; i++) {
        if (typeof this.options.onError != 'undefined' && this.options.onError != null && this.options.onError) {
          this.options.onError(errors[i]);
        }
      }

      return;
    }

    if (next_id >= this.steps.length - 1) {
      if (typeof this.options.onFinish != 'undefined' && this.options.onFinish != null && this.options.onFinish) {
        this.options.onFinish(current_id);
      }
      this.emit('bulmasteps:finish', current_id);
    }
    if (next_id < this.steps.length) {
      this.complete_step(current_id);
      this.activate_step(next_id);
    }
  }

  previous_step() {
    var current_id = this.get_current_step_id();
    if (current_id == null) {
      return;
    }

    this.uncomplete_step(current_id - 1);
    this.activate_step(current_id - 1);
  }

  /**
   * Activate a single step,
   * will deactivate all other steps.
   */
  activate_step(step_id) {
    this.updateActions(this.steps[step_id]);

    for (var i = 0; i < this.steps.length; i++) {
      var _step = this.steps[i];

      if (_step == this.steps[step_id]) {
        continue;
      }

      this.deactivate_step(i);
    }

    this.steps[step_id].classList.add(this.options.active_class);
    if (typeof this.contents[step_id] !== 'undefined') {
      this.contents[step_id].classList.add(this.options.active_class);
    }

    if (typeof this.options.onShow != 'undefined' && this.options.onShow != null && this.options.onShow) {
      this.options.onShow(step_id);
    }

    this.emit('bulmasteps:step:show', step_id);
  }

  complete_step(step_id) {
    this.steps[step_id].classList.add(this.options.completed_class);
    this.emit('bulmasteps:step:completed', step_id);
  }

  uncomplete_step(step_id) {
    this.steps[step_id].classList.remove(this.options.completed_class);
    this.emit('bulmasteps:step:uncompleted', step_id);
  }

  deactivate_step(step_id) {
    this.steps[step_id].classList.remove(this.options.active_class);
    if (typeof this.contents[step_id] !== 'undefined') {
      this.contents[step_id].classList.remove(this.options.active_class);
    }
  }
}
