import { Facet } from './Facet';
import { FacetValue } from './FacetValue';
import { $$ } from '../../utils/Dom';
import { Utils } from '../../utils/Utils';
import { l } from '../../strings/Strings';
import { Component } from '../Base/Component';
import * as _ from 'underscore';
import { SVGIcons } from '../../utils/SVGIcons';
import { SVGDom } from '../../utils/SVGDom';

export class ValueElementRenderer {
  public listItem: HTMLElement;
  public label: HTMLElement;
  public checkbox: HTMLElement;
  public stylishCheckbox: HTMLElement;
  public valueCaption: HTMLElement;
  public valueCount: HTMLElement;
  public icon: HTMLElement;
  public excludeIcon: HTMLElement;
  public computedField: HTMLElement;
  private facetValueLabelWrapper: HTMLElement;

  constructor(public facet: Facet, public facetValue: FacetValue) {}

  public withNo(element: HTMLElement[]): ValueElementRenderer;
  public withNo(element: HTMLElement): ValueElementRenderer;
  public withNo(element: any): ValueElementRenderer {
    if (_.isArray(element)) {
      _.each(element, (e: HTMLElement) => {
        if (e) {
          $$(e).detach();
        }
      });
    } else {
      if (element) {
        $$(element).detach();
      }
    }
    return this;
  }

  public build(): ValueElementRenderer {
    this.buildListItem();
    this.initAndAppendLabel();
    this.initAndAppendExcludeIcon();
    this.setCssClassOnListValueElement();
    this.addAccessibilityAttributesToTargetElement();
    return this;
  }

  public setCssClassOnListValueElement(): void {
    $$(this.listItem).toggleClass('coveo-selected', this.facetValue.selected);
    $$(this.listItem).toggleClass('coveo-excluded', this.facetValue.excluded);
  }

  public get accessibleElement() {
    return this.stylishCheckbox;
  }

  protected buildExcludeIcon(): HTMLElement {
    const isExcluded = this.facetValue.excluded;
    const excludeIcon = $$('div', {
      ariaLabel: l('ExcludeValueWithResultCount', this.caption, l('ResultCount', this.count, parseInt(this.count, 10))),
      className: 'coveo-facet-value-exclude',
      tabindex: 0,
      role: 'button',
      ariaPressed: isExcluded.toString()
    }).el;
    this.addFocusAndBlurEventListeners(excludeIcon);
    excludeIcon.innerHTML = isExcluded ? SVGIcons.icons.plus : SVGIcons.icons.checkboxHookExclusionMore;
    SVGDom.addClassToSVGInContainer(excludeIcon, isExcluded ? 'coveo-facet-value-unexclude-svg' : 'coveo-facet-value-exclude-svg');
    SVGDom.addAttributesToSVGInContainer(excludeIcon, { 'aria-hidden': 'true' });
    return excludeIcon;
  }

  protected buildValueComputedField(): HTMLElement {
    const computedField = this.facetValue.getFormattedComputedField(this.facet.options.computedFieldFormat);
    if (Utils.isNonEmptyString(computedField)) {
      const elem = $$('span', {
        className: 'coveo-facet-value-computed-field'
      }).el;
      $$(elem).text(computedField);
      return elem;
    } else {
      return undefined;
    }
  }

  protected buildValueCheckbox(): HTMLElement {
    const checkbox = $$('input', {
      type: 'checkbox',
      ariaHidden: true,
      ariaLabel: this.ariaLabel
    }).el;

    this.facetValue.selected ? checkbox.setAttribute('checked', 'checked') : checkbox.removeAttribute('checked');
    this.facetValue.excluded ? checkbox.setAttribute('disabled', 'disabled') : checkbox.removeAttribute('disabled');

    Component.pointElementsToDummyForm(checkbox);
    return checkbox;
  }

  protected buildValueStylishCheckbox(): HTMLElement {
    const checkbox = $$('div', {
      className: 'coveo-facet-value-checkbox',
      tabindex: 0
    }).el;
    checkbox.innerHTML = SVGIcons.icons.checkboxHookExclusionMore;
    SVGDom.addClassToSVGInContainer(checkbox, 'coveo-facet-value-checkbox-svg');
    this.addFocusAndBlurEventListeners(checkbox);
    return checkbox;
  }

  protected buildValueIcon(): HTMLElement {
    const icon = this.getValueIcon();
    if (Utils.exists(icon)) {
      return $$('img', {
        className: 'coveo-facet-value-icon coveo-icon',
        src: this.getValueIcon()
      }).el;
    } else {
      return this.buildValueIconFromSprite();
    }
  }

  protected getValueIcon(): string {
    if (Utils.exists(this.facet.options.valueIcon)) {
      return this.facet.options.valueIcon(this.facetValue);
    } else {
      return undefined;
    }
  }

  protected buildValueIconFromSprite(): HTMLElement {
    return $$('div', {
      className: 'coveo-facet-value-icon coveo-icon ' + this.facet.options.field.substr(1) + ' ' + this.facetValue.value
    }).el;
  }

  protected buildValueCaption(): HTMLElement {
    const valueCaption = $$('span', {
      className: 'coveo-facet-value-caption',
      title: this.caption,
      'data-original-value': this.facetValue.value
    }).el;

    $$(valueCaption).text(this.caption);
    return valueCaption;
  }

  protected buildValueCount(): HTMLElement {
    if (Utils.isNonEmptyString(this.count)) {
      const countElement = $$('span', {
        className: 'coveo-facet-value-count'
      }).el;
      $$(countElement).text(this.count);
      return countElement;
    } else {
      return undefined;
    }
  }

  private get caption() {
    return this.facet.getValueCaption(this.facetValue);
  }

  private get count() {
    return this.facetValue.getFormattedCount();
  }

  private addFocusAndBlurEventListeners(elem: HTMLElement) {
    $$(elem).on('focus', () => $$(this.listItem).addClass('coveo-focused'));
    $$(elem).on('blur', () => $$(this.listItem).removeClass('coveo-focused'));
  }

  private buildListItem() {
    this.listItem = $$('li', { className: 'coveo-facet-value coveo-facet-selectable', ariaLabel: this.ariaLabel }).el;

    if (!$$(this.listItem).canHandleEvent('touchstart')) {
      $$(this.listItem).addClass('coveo-with-hover');
    }

    this.listItem.setAttribute('data-value', this.facetValue.value);
  }

  private initAndAppendLabel() {
    this.label = $$('label', { className: 'coveo-facet-value-label' }).el;
    this.tryToInitAndAppendComputedField();
    this.initAndAppendFacetValueLabelWrapper();
    this.listItem.appendChild(this.label);
  }

  private initAndAppendExcludeIcon() {
    this.excludeIcon = this.buildExcludeIcon();
    this.attachExcludeIconEventHandlers();
    this.listItem.appendChild(this.excludeIcon);
  }

  private attachExcludeIconEventHandlers() {
    $$(this.excludeIcon).on('mouseover', () => {
      $$(this.listItem).addClass('coveo-facet-value-will-exclude');
    });

    $$(this.excludeIcon).on('mouseout', () => {
      $$(this.listItem).removeClass('coveo-facet-value-will-exclude');
    });
  }

  private tryToInitAndAppendComputedField() {
    if (!Utils.exists(this.facetValue.computedField)) {
      return;
    }

    this.computedField = this.buildValueComputedField();

    if (!this.computedField) {
      return;
    }

    this.label.appendChild(this.computedField);
    $$(this.label).addClass('coveo-with-computed-field');
  }

  private initAndAppendFacetValueLabelWrapper() {
    this.facetValueLabelWrapper = $$('div', { className: 'coveo-facet-value-label-wrapper' }).el;

    this.initAndAppendCheckbox();
    this.initAndAppendStylishCheckbox();
    this.initAndAppendValueCaption();
    this.initAndAppendValueCount();

    this.label.appendChild(this.facetValueLabelWrapper);
  }

  private initAndAppendCheckbox() {
    this.checkbox = this.buildValueCheckbox();
    this.facetValueLabelWrapper.appendChild(this.checkbox);
  }

  private initAndAppendStylishCheckbox() {
    this.stylishCheckbox = this.buildValueStylishCheckbox();
    this.facetValueLabelWrapper.appendChild(this.stylishCheckbox);
  }

  private initAndAppendValueCount() {
    this.valueCount = this.buildValueCount();

    if (!this.valueCount) {
      return;
    }

    this.facetValueLabelWrapper.appendChild(this.valueCount);
  }

  private initAndAppendValueCaption() {
    this.valueCaption = this.buildValueCaption();
    this.facetValueLabelWrapper.appendChild(this.valueCaption);
  }

  private addAccessibilityAttributesToTargetElement() {
    const el = this.accessibleElement;
    el.setAttribute('aria-label', this.ariaLabel);
    el.setAttribute('role', 'button');
    el.setAttribute('aria-pressed', this.ariaPressed);
  }

  private get ariaLabel() {
    const resultCount = l('ResultCount', this.count, parseInt(this.count, 10));
    return `${l('IncludeValueWithResultCount', this.caption, resultCount)}`;
  }

  private get ariaPressed() {
    if (this.facetValue.excluded) {
      return 'mixed';
    }
    return this.facetValue.selected ? 'true' : 'false';
  }
}
