'use strict';

var inventoryFilterServiceClass = Class.extend({
    hostSearchAttribute: 'cfHostSearchQuery',
    processFilters: function (filters) {
        var processedFilters = {};

        if (!filters || filters.length === 0) {
            return null;
        }

        angular.forEach(filters, function (value, key) {
            var processedFilterItem = this.processFilterItem(value);
            this.combineFilters(processedFilters, processedFilterItem);
        }, this);
        return Object.keys(processedFilters).length !== 0 ? processedFilters : null;
    },

    hostsFilterToEntries: function (hostsFilters) {
        const {includes, excludes} = hostsFilters;

        let processedFilters = {includes: {}, excludes: {}};
        if (includes) {
            processedFilters.includes.hostkey = includes?.data || Object.keys(includes);
        }
        if (excludes) {
            processedFilters.excludes.hostkey = excludes?.data || Object.keys(excludes);
        }
        return processedFilters;
    },

    processEntriesFilters: function (SQL) {
        let processedFilters = {};
        let entriesFilter = SQL.entriesFilter;
        const includeAdditionally = SQL.hasOwnProperty('filters') && SQL.filters && SQL.filters.length > 0;
        if (entriesFilter && Object.keys(entriesFilter.includes).length > 0) {
            processedFilters.includes = {
                includeAdditionally,
                entries: entriesFilter.includes
            }
        }

        if (entriesFilter && Object.keys(entriesFilter.excludes).length > 0) {
            processedFilters.excludes = {
                entries: entriesFilter.excludes
            }
        }
        return Object.keys(processedFilters).length > 0 ? processedFilters : null;
    },

    processClassFilters: function (filters) {
        let classes = [];

        if (!filters || filters.length === 0) {
            return classes;
        }

        angular.forEach(filters, function (value) {
            if (value.type === 'class') {
                classes.push(value.value);
            }
        });

        return classes;
    },

    combineFilters: function (processedFilters, processedFilterItem) {
        if (typeof processedFilterItem !== 'object' || processedFilterItem === null) {
            return ;
        }
        var filterKey = Object.keys(processedFilterItem)[0];
        if (processedFilters.hasOwnProperty(filterKey)) {
            var combineFilters = {};
            var currentValue = processedFilters[filterKey];
            let condition = Object.keys(processedFilterItem[filterKey])[0];
            //set value as array in case of filters with the same attribute naprocessFiltersme and condition
            if (processedFilters[filterKey].hasOwnProperty(condition)) {
                let arrayValue = Array.isArray(processedFilters[filterKey][condition]) ? processedFilters[filterKey][condition] : [processedFilters[filterKey][condition]];
                arrayValue.push(processedFilterItem[filterKey][condition]);
                processedFilterItem[filterKey][condition] = arrayValue;
            }
            Object.assign(combineFilters, currentValue);
            Object.assign(combineFilters, processedFilterItem[filterKey]);
            processedFilters[filterKey] = combineFilters;
        } else {
            Object.assign(processedFilters, processedFilterItem);
        }
    },

    /**
     * Process filter item according to type
     * @param filterItem
     * @returns object|null
     */
    processFilterItem: function (filterItem) {
        if (filterItem.value === undefined || filterItem.type === 'class') {
            return null;
        }

        var filterItemObj = {},
            filterItemProcessed = {},
            attributeName = filterItem['attribute_name'].replace('attribute_name=', '');


        switch (filterItem.type) {
            case 'slist':
                filterItemProcessed = this._processlist(filterItem);
                break;
            case 'string':
                filterItemProcessed = this._processString(filterItem);
                break;
            case 'int':
            case 'real':
                filterItemProcessed = this._processNumeric(filterItem);
                break;
            case 'date':
                filterItemProcessed = this._processDate(filterItem);
                break;
            case 'context':
                filterItemProcessed = this._processString(filterItem);
                break;
        }

        filterItemObj[attributeName] = filterItemProcessed;

        return filterItemObj;
    },

    /**
     * Process filter item for type SList
     * @param filter
     * @returns object|null
     */
    _processlist: function (filter) {
        var value = filter.value.replace(',', '%'),
            realCondition = '',
            resultObj = {};

        switch (filter.condition) {
            case '=':
                realCondition = INVENTORY_FILTER_OPERATORS['matches'];
                break;
            case '!=':
                realCondition = INVENTORY_FILTER_OPERATORS['not_match'];
                break;
            default:
                realCondition = INVENTORY_FILTER_OPERATORS[filter.condition];
                break;
        }

        resultObj[realCondition] = value;

        return resultObj
    },

    /**
     * Process filter item for type String
     * @param filter
     * @returns object
     */
    _processString: function (filter) {
        var value = filter.value,
            resultObj = {};
        var realCondition = INVENTORY_FILTER_OPERATORS[filter.condition];
        resultObj[realCondition] = value;

        return resultObj
    },

    /**
     * Process filter item for type Numeric
     * @param filter
     * @returns object
     */
    _processNumeric: function (filter) {
        var value = filter.value,
            realCondition = '',
            resultObj = {};

        realCondition = INVENTORY_FILTER_OPERATORS[filter.condition];

        resultObj[realCondition] = value;

        return resultObj
    },

    /**
     * Process filter item for type Date
     * @param filter
     * @returns object
     */
    _processDate: function (filter) {
        var value = filter.value,
            realCondition = '',
            resultObj = {};

        realCondition = INVENTORY_FILTER_OPERATORS[filter.condition];

        resultObj[realCondition] = value;

        return resultObj
    },

    convertFilterObjectToFilters: async function (filtersObject, attributesMapping) {
        let self = this;
        let filters = [];

        if (!filtersObject && Object.keys(filtersObject).length === 0) {
            return null;
        }


        if (filtersObject.hasOwnProperty('filter')) {
            angular.forEach(filtersObject.filter, function (invFilters, invAttribute) {
                const attrKey = Object.keys(attributesMapping).find(key => attributesMapping[key].label === invAttribute);
                angular.forEach(invFilters, function (value, condition) {
                    // host search attribute is a virtual column and does not exist in the attributes map
                    const mappedAttribute = (invAttribute === self.hostSearchAttribute) ?
                        self.filterFromSearchQuery(value) :
                        attributesMapping[attrKey];
                    let filter = {...mappedAttribute, condition};
                    // if values is array, make separate filter for every item
                    // this happens when you select same attribute and operator for different filters
                    if (Array.isArray(value)) {
                        value.forEach(v => {
                            filters.push({...filter, value: v});
                        })
                    } else {
                        filters.push({...filter, value});
                    }
                })
            }, this);
        }

        if (filtersObject.hasOwnProperty('hostContextInclude')) {
            for (const value of filtersObject.hostContextInclude) {
                filters.push({type: 'class', value, condition: 'matches'});
            }
        }

        return filters;
    },

    filterFromSearchQuery: function (searchQuery) {
       return {
           "id": `attribute_name=attribute_name=${this.hostSearchAttribute}`,
           "attribute_name": `attribute_name=${this.hostSearchAttribute}`,
           "category": "search",
           "readonly": 1,
           "type": "string",
           "convert_function": null,
           "keyname": null,
           "enabled": 1,
           "label": "Host search",
           "value": searchQuery,
           "condition": "matches"
       }
    },

    isAttributeSearchQuery: function (attributeName) {
        return attributeName.includes(this.hostSearchAttribute)
    }

});

(function () {
    var inventoryFilterServiceClassProvider = Class.extend({
        instance: new inventoryFilterServiceClass(),
        $get: ['reportService', function (reportService) {
            this.instance.reportService = reportService;
            return this.instance;
        }]
    });

    angular.module('inventoryFilterServiceModule', [])
        .provider('inventoryFilterService', inventoryFilterServiceClassProvider);
}());