import { EnumSelected } from './../../../model/common-model';
import { BindingEngine, Disposable } from "aurelia-binding";
import { Container } from "aurelia-framework";
import { I18N } from "aurelia-i18n";

export class EnumFilterHelper {
    public filterValues: Array<EnumSelected>;
    public selectedIds: Array<number> = [];
    private selectedIdInternalChange: boolean = false;

    private filterValueChangedCallback: (newVal: boolean, oldVal: boolean) => {};

    private disposables: Array<Disposable> = [];
    private bindingEngine: BindingEngine;
    private i18n: I18N;

    constructor(filterValueChangedCallback, private enumeration, private category: string) {
        this.bindingEngine = Container.instance.get(BindingEngine);
        this.i18n = Container.instance.get(I18N);


        this.filterValueChangedCallback = filterValueChangedCallback;
    }

    public isFilterActive(): boolean {
        return this.filterValues?.some(x => x.selected);
    }

    public async onOpenDropDown() {
        this.dispose();
        let oldFilterValues = this.filterValues;
        this.getEnumerated();
        if (oldFilterValues && oldFilterValues.length > 0) {
            oldFilterValues.forEach(oldFilterValue => {
                if (this.filterValues && this.filterValues.some(x => x.key == oldFilterValue.key))
                    this.filterValues.find(x => x.key == oldFilterValue.key).selected = oldFilterValue.selected;
            });
            this.selectedIds.splice(0);
            this.selectedIds.push(...this.filterValues.filter(x => x.selected).map(x => x.index));
        }
        else {
            this.resetFilter();
        }
    }

    public filterValuesChanged(newVal: boolean, oldVal: boolean) {
        if (newVal != oldVal) {
            this.selectedIdInternalChange = true;
            this.selectedIds.splice(0);
            this.selectedIds.push(...this.filterValues.filter(x => x.selected).map(x => x.index));

            if (this.filterValueChangedCallback) {
                this.filterValueChangedCallback(newVal, oldVal);
            }

            this.selectedIdInternalChange = false;
        }
    }

    public setSelectedValues() {
        this.selectedIdInternalChange = true;
        this.selectedIds.splice(0);
        this.selectedIds.push(...this.filterValues.filter(x => x.selected).map(x => x.index));
        this.selectedIdInternalChange = false;
    }

    public getEnumerated(existing: Array<EnumSelected> = null) {
        this.dispose();
        this.filterValues = new Array<EnumSelected>();
        let objectKeys: Array<string> = Object.keys(this.enumeration);
        let nbEnum: number = objectKeys.length / 2;
        for (let i = 0; i < nbEnum; i++) {
            let objectIndex: number = parseInt(objectKeys[i]);
            let objectKey: string = objectKeys[nbEnum + i];

            let filterValue = { index: objectIndex, key: (objectKey[0].toLowerCase() + objectKey.substring(1)), selected: false, hide: false };
            filterValue.selected = existing?.find(x => x.index == filterValue.index)?.selected ?? false;

            this.filterValues.push(filterValue);
            let disposable = this.bindingEngine.propertyObserver(filterValue, 'selected').subscribe(this.filterValuesChanged.bind(this));
            this.disposables.push(disposable);
        }
        this.disposables.push(this.bindingEngine.collectionObserver(this.selectedIds).subscribe((changeRecords) => {
            if (!this.selectedIdInternalChange) {
                if (changeRecords?.length > 0 && changeRecords[0].removed.length > 0) {
                    changeRecords[0].removed.forEach(id => {
                        this.filterValues.find(x => x.index == id).selected = false;
                    });
                }
                this.selectedIds.forEach(id => {
                    this.filterValues.find(x => x.index == id).selected = true;
                })
            }
        }));
    }

    public resetFilter() {
        if (this.filterValues) {
            this.filterValues.forEach(filterValue => {
                filterValue.selected = false;
            });
        }
    }

    public setupContentGui() {
        return `
      <div class="floating-filter__body__enum">
        <div class="floating-filter__body__enum__list">
          <div repeat.for="filterValue of filterHelper.filterValues" if.bind="!filterValue.hide" class="floating-filter__body__enum__list__elem">
            <ui-checkbox checked.bind="filterValue.selected" t="[title]\${filterHelper.category + '.' + filterValue.key}">
              \${filterHelper.category + '.' + filterValue.key | t}
            </ui-checkbox>
          </div>
        </div>
      </div>`;
    }

    public setupContentGuiSideFilter(): string {
        return `
    <div class="col s12 m12 l12">
      <ui-field label.bind="params.colDef.headerName">
        <ui-select t="[placeholder]general.chooseAnOption" value.bind="filterHelper.selectedIds" multiple>
          <option repeat.for="value of filterHelper.filterValues" value.bind="value.index">
            \${filterHelper.category + '.' + value.key | t}
          </option>
        </ui-select>
      </ui-field>
    </div>`;
    }

    public getValue(): Array<EnumSelected> {
        return this.filterValues.filter(x => x.selected);
    }

    public getModelAsString(): string {
        if (this.filterValues && this.filterValues.some(x => x.selected)) {
            return `${this.i18n.tr('grid.filterOoo', { ns: "common" })} <span style='background-color: gray; color: white; padding: 0 5px 0 5px; border-radius: 20px;'>${this.getValue().length}</span>`;
        }
        else {
            return this.i18n.tr('grid.noFilter', { ns: "common" });
        }
    }

    private dispose() {
        this.disposables.forEach(disposable => disposable.dispose());
        this.disposables.splice(0);
    }
}