import {AgPromise, IDoesFilterPassParams, IFilterComp, IFilterParams} from "ag-grid-community";

export class SetFilter implements IFilterComp {

  private OPTION_TEMPLATE = `<label class="ag-set-filter-item">
                               <input type="checkbox" class="ag-filter-checkbox" checked/>
                               <span class="ag-filter-value"></span>
                             </label>`;

  private eGui!: HTMLDivElement;
  private selectAll: HTMLInputElement;
  private checkboxes: HTMLInputElement[] = [];
  private values: any[] = [];
  private initialValues: any[] = [];
  private filterActive: boolean;
  private filterChangedCallback!: (additionalEventAttributes?: any) => void;
  private filterParams!: IFilterParams;
  private valueType: string;

  init(params: IFilterParams): void {
    this.eGui = document.createElement('div');
    this.eGui.className = 'ag-set-filter';
    let index = 0;
    this.selectAll = this.initCheckBox('selectAll', 'Все', index);
    this.checkboxes.push(this.selectAll);

    const allValues: any[] = [];
    params.api.forEachNode((node) => {
      allValues.push(node.data[params.colDef.field]);
    });

    allValues
        .sort((n1, n2) => n1 > n2 ? 1 : n1 < n2 ? -1 : 0)
        .forEach(value => {
          if (this.values.includes(value)) {
            return;
          }
          index++;
          let id = `option-${index}`;
          let checkbox = this.initCheckBox(id, value, index);
          this.checkboxes.push(checkbox);
          this.values.push(value);
        });

    this.initialValues = this.values.slice();
    this.filterParams = params;
    this.filterActive = false;
    this.filterChangedCallback = params.filterChangedCallback;

    if (this.values.length > 0) {
      this.valueType = typeof this.values[0];
    }
  };

  private initCheckBox(id: string, value: string, index: number): HTMLInputElement {
    this.eGui.insertAdjacentHTML('beforeend', this.OPTION_TEMPLATE);
    (this.eGui.querySelectorAll('.ag-filter-value')[index] as HTMLElement).textContent = value;
    let checkbox = this.eGui.querySelectorAll('.ag-filter-checkbox')[index] as HTMLInputElement;
    checkbox.setAttribute('id', id);
    checkbox.addEventListener('change', this.onCheckBoxChanged.bind(this));
    return checkbox;
  }

  getGui(): HTMLDivElement {
    return this.eGui;
  };

  onCheckBoxChanged(event: any) {
    let checked = event.target.checked;

    if (event.target === this.selectAll) {
      this.checkboxes.forEach(checkbox => checkbox.checked = checked);
      this.values = checked ? this.initialValues.slice() : [];
    }
    else {
      let value = event.target.nextElementSibling.textContent;
      value = this.valueType === 'number' ? +value : value;

      if (checked) {
        this.values.push(value);

        if (this.values.length == this.initialValues.length) {
          this.selectAll.checked = true;
        }
      }
      else {
        let index = this.values.indexOf(value);
        this.values.splice(index, 1);
        this.selectAll.checked = false;
      }
    }
    this.filterActive = !this.selectAll.checked;
    this.filterChangedCallback();
  }

  doesFilterPass(params: IDoesFilterPassParams): boolean {
    let { field } = this.filterParams.colDef;
    return this.values.includes(params.data[field]);
  }

  getModel(): any {
    return this.isFilterActive() ? { value: this.values } : null;
  }

  isFilterActive(): boolean {
    return this.filterActive;
  }

  setModel(model: any): void | AgPromise<void> {
    this.values = model == null ? this.initialValues.slice() : model.value;
    let predicate = checkbox => model == null ? true : model.value.includes(checkbox.value);
    this.checkboxes.filter(predicate)
        .forEach(checkbox => checkbox.checked = true);
    this.filterActive = !this.selectAll.checked;
    this.filterChangedCallback();
  }

  destroy(): void {
    this.checkboxes.forEach(checkBox => checkBox.removeEventListener('change', this.onCheckBoxChanged.bind(this)));
  }
}
