import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';

class Controller extends Section {
    constructor($element, $) {
        super($element, $);
        this.itemTypes = [];
        this._tagGroups = [];

        // Static autocomplete data
        this.orderWays = [
            {way: 'ASC', name: 'Ascendant'},
            {way: 'DESC', name: 'Descendant'},
        ];
        this.defaultOrderFields = [
            {field: 'relevancy DESC, name', name: 'Relevancy', priority: 999},
            {field: 'showOrder, price', name: 'Color and price', priority: 999},
            {field: 'name', name: 'Name', priority: 999},
            {field: 'price', name: 'Price', priority: 999}
        ];
        this.orderFields = [].concat(this.defaultOrderFields);
        this._orderWay = this.orderWays[0].way;
        this.orderField = this.orderFields[0].field;
    }

    $onChanges() {
        this.getData().then(() => {
            if (this.order && this.order.isConfirmed)
                this.$state.go('order.card.line');
        });
    }

    getData() {
        return this.$http.get(`Orders/${this.$params.id}`)
            .then(res => this.order = res.data);
    }

    /**
     * Fills order autocomplete with tags
     * obtained from last filtered
     */
    get order() {
        return this._order;
    }

    /**
     * Sets filter values from state params
     *
     * @param {Object} value - Order data
     */
    set order(value) {
        this._order = value;

        if (!value) return;

        this.$.$applyAsync(() => {
            if (this.$params.categoryId)
                this.categoryId = parseInt(this.$params.categoryId);

            if (this.$params.typeId)
                this.typeId = parseInt(this.$params.typeId);

            if (this.$params.tagGroups)
                this.tagGroups = JSON.parse(this.$params.tagGroups);
        });
    }

    get items() {
        return this._items;
    }

    set items(value) {
        this._items = value;

        if (!value) return;

        this.fetchResultTags(value);
        this.buildOrderFilter();
    }

    get categoryId() {
        return this._categoryId;
    }

    set categoryId(value = null) {
        this._categoryId = value;
        this.itemTypes = [];
        this.typeId = null;

        this.updateStateParams();

        if (this.tagGroups.length > 0)
            this.applyFilters();

        if (value)
            this.updateItemTypes();
    }

    changeCategory(id) {
        if (this._categoryId == id) id = null;
        this.categoryId = id;
    }

    get typeId() {
        return this._typeId;
    }

    set typeId(value) {
        this._typeId = value;

        this.updateStateParams();

        if (value || this.tagGroups.length > 0)
            this.applyFilters();
    }

    get tagGroups() {
        return this._tagGroups;
    }

    set tagGroups(value) {
        this._tagGroups = value;

        this.updateStateParams();

        if (value.length)
            this.applyFilters();
    }

    /**
     * Get order way ASC/DESC
     */
    get orderWay() {
        return this._orderWay;
    }

    set orderWay(value) {
        this._orderWay = value;
        if (value) this.applyOrder();
    }

    /**
     * Returns the order way selection
     */
    get orderSelection() {
        return this._orderSelection;
    }

    set orderSelection(value) {
        this._orderSelection = value;

        if (value) this.applyOrder();
    }

    /**
     * Apply order to model
     */
    applyOrder() {
        if (this.typeId || this.tagGroups.length > 0)
            this.$.model.addFilter(null, {orderBy: this.getOrderBy()});
    }

    /**
     * Returns order param
     *
     * @return {Object} - Order param
     */
    getOrderBy() {
        const isTag = !!(this.orderSelection && this.orderSelection.isTag);
        return {
            field: this.orderField,
            way: this.orderWay,
            isTag: isTag
        };
    }

    /**
     * Refreshes item type dropdown data
     */
    updateItemTypes() {
        let params = {
            itemCategoryId: this.categoryId
        };

        const query = `Orders/${this.order.id}/getItemTypeAvailable`;
        this.$http.get(query, {params}).then(res =>
            this.itemTypes = res.data);
    }

    /**
     * Search by tag value
     * @param {object} event
     */
    onSearchByTag(event) {
        const value = this.$.search.value;
        if (event.key !== 'Enter' || !value) return;
        this.tagGroups.push({values: [{value: value}]});
        this.$.search.value = null;
        this.updateStateParams();
        this.applyFilters();
    }

    remove(index) {
        this.tagGroups.splice(index, 1);
        this.updateStateParams();

        if (this.tagGroups.length >= 0 || this.itemId || this.typeId)
            this.applyFilters();
    }

    removeItemId() {
        this.itemId = null;
        this.$.searchbar.doSearch({}, 'bar');
    }

    removeItemName() {
        this.itemName = null;
        this.$.searchbar.doSearch({}, 'bar');
    }

    applyFilters(filter = {}) {
        let newParams = {};
        let newFilter = Object.assign({}, filter);
        const model = this.$.model;

        if (this.categoryId)
            newFilter.categoryFk = this.categoryId;

        if (this.typeId)
            newFilter.typeFk = this.typeId;

        newParams = {
            orderFk: this.$params.id,
            orderBy: this.getOrderBy(),
            tagGroups: this.tagGroups,
        };

        return model.applyFilter({where: newFilter}, newParams);
    }

    openPanel(event) {
        if (event.defaultPrevented) return;
        event.preventDefault();

        this.panelFilter = {};
        this.$.popover.show(this.$.search.element);
    }

    onPanelSubmit(filter) {
        this.$.popover.hide();
        const values = filter.values;
        const nonEmptyValues = values.filter(tagValue => {
            return tagValue.value;
        });

        filter.values = nonEmptyValues;

        if (filter.tagFk && nonEmptyValues.length) {
            this.tagGroups.push(filter);
            this.updateStateParams();
            this.applyFilters();
        }
    }

    /**
     * Updates url state params from filter values
     */
    updateStateParams() {
        const params = {};

        params.categoryId = undefined;
        if (this.categoryId)
            params.categoryId = this.categoryId;

        params.typeId = undefined;
        if (this.typeId)
            params.typeId = this.typeId;

        params.tagGroups = undefined;
        if (this.tagGroups && this.tagGroups.length)
            params.tagGroups = JSON.stringify(this.sanitizedTagGroupParam());

        this.$state.go(this.$state.current.name, params);
    }

    sanitizedTagGroupParam() {
        const tagGroups = [];
        for (let tagGroup of this.tagGroups) {
            const tagParam = {values: []};

            for (let tagValue of tagGroup.values)
                tagParam.values.push({value: tagValue.value});

            if (tagGroup.tagFk)
                tagParam.tagFk = tagGroup.tagFk;

            if (tagGroup.tagSelection) {
                tagParam.tagSelection = {
                    name: tagGroup.tagSelection.name
                };
            }

            tagGroups.push(tagParam);
        }

        return tagGroups;
    }

    fetchResultTags(items) {
        const resultTags = [];
        for (let item of items) {
            for (let itemTag of item.tags) {
                const alreadyAdded = resultTags.findIndex(tag => {
                    return tag.tagFk == itemTag.tagFk;
                });

                if (alreadyAdded == -1)
                    resultTags.push({...itemTag, priority: 1});
                else
                    resultTags[alreadyAdded].priority += 1;
            }
        }
        this.resultTags = resultTags;
    }

    buildOrderFilter() {
        const filter = [].concat(this.defaultOrderFields);
        for (let tag of this.resultTags)
            filter.push({...tag, field: tag.id, isTag: true});

        this.orderFields = filter;
    }

    onSearch(params) {
        if (!params) return;

        this.itemId = null;
        this.itemName = null;

        if (params.search) {
            if (/^\d+$/.test(params.search)) {
                this.itemId = params.search;
                return this.applyFilters({
                    'i.id': params.search
                });
            } else {
                this.itemName = params.search;
                return this.applyFilters({
                    'i.name': {like: `%${params.search}%`}
                });
            }
        } else return this.applyFilters();
    }

    formatTooltip(tagGroup) {
        const tagValues = tagGroup.values;

        let title = '';
        if (tagGroup.tagFk) {
            const tagName = tagGroup.tagSelection.name;
            title += `${tagName}: `;
        }

        for (let [i, tagValue] of tagValues.entries()) {
            if (i > 0) title += ', ';
            title += `"${tagValue.value}"`;
        }

        return `${title}`;
    }
}

ngModule.vnComponent('vnOrderCatalog', {
    template: require('./index.html'),
    controller: Controller
});