'use strict';

const baseGroupController = BaseController.extend({
    init: function ($scope, $q, $routeParams, $modal, $cookies, groupsService, inventoryFilterService, inventoryDataService, inventoryService, inventoryHelper, commonHelper, paginationService) {
        this._super($scope);
        this.$modal = $modal;
        this.$q = $q;
        this.$scope = $scope;
        this.groupsService = groupsService;
        this.inventoryFilterService = inventoryFilterService;
        this.inventoryService = inventoryService;
        this.inventoryDataService = inventoryDataService;
        this.inventoryHelper = inventoryHelper;
        this.commonHelper = commonHelper;
        paginationService.paginationReset();
        this.$scope.paginator = paginationService;
        this.$scope.can_edit = true;
        this.$scope.data = {
            groupName: ''
        };
        this.$scope.maxNameLength = MAX_NAME_LENGTH;


        this.$scope.grouplist = $cookies.get('grouplist');
        this.$scope.personalgroup = this instanceof personalGroupController;
        this.$scope.shared = false;
        this.$scope.widget = {type: 'pie', 'attributeName': 'OS', config: {}};

        this.$scope.UI = {}

        this.$scope.isFiltersChanged = false;

        this.$scope.groupExists = true;
        common.globalSpinner.show();

        this.defaultColumns = ['Host name', 'OS', 'Architecture', 'IPv4 addresses', 'MAC addresses'];

        this.$scope.groupId = $routeParams.id;
        this.initVIEWParams();
        this.initSQLParams();

        this.handleGroupLoadingError = error => {
            if (error.status === 404) {
                this.$scope.groupExists = false;
            } else {
                notify.error(error.data);
            }
            common.globalSpinner.hide();
        };

        this.handleGroupLoading = response => {
            this.$scope.group = response.data;
            this.$scope.groupExists = true;
            common.globalSpinner.hide();
        };

        const lastUriItem = location.pathname.split('/').slice(-1)[0];
        if (lastUriItem == 'data') {
            this.groupsService.get(this.$scope.groupId).then(this.handleGroupLoading).catch(this.handleGroupLoadingError);
        }

        this.$scope.sortReorder = this.sortReorder.bind(this);
        this.$scope.cancelFilterChanges = this.cancelFilterChanges.bind(this);
        this.$scope.clearAllFilters = this.clearAllFilters.bind(this);
        this.$scope.saveGroup = this.saveGroup.bind(this);
        this.$scope.openInventoryReport = this.openInventoryReport.bind(this);
        this.$scope.saveGroupTitleFn = this.saveGroupTitleFn.bind(this);
    },

    defineListeners: function () {
        let self = this;

        this.$scope.$watch('group', group => {
            if (!group) return;

            if (!(this instanceof sharedGroupDataController) && !(this instanceof personalGroupDataController)) {
                this.inventoryFilterService.convertFilterObjectToFilters(group.filter, this.$scope.UI.CFE_mapping).then(parsedFilters => {
                    this.$scope.SQL.filters = parsedFilters;
                    this.$scope.SqlOriginal = angular.copy(self.$scope.SQL);
                    this.$scope.isFiltersChanged = false;
                    this.loadInventoryTable(true);
                    this.loadWidget();
                });

                this.$scope.SQL.entriesFilter = (group.filter.hasOwnProperty('hostsFilter')) ?
                    this.inventoryFilterService.hostsFilterToEntries(group.filter.hostsFilter) :
                    {
                        ...this.$scope.SQL.entriesFilter,
                        ...{includes: (group.filter.hostFilter?.includes?.entries || {})},
                        ...{excludes: (group.filter.hostFilter?.excludes?.entries || {})}
                    };
            }
            this.$scope.data.groupName = group.name;
        }, true)

        self.$scope.$watch('UI', function (ui) {
            if (ui && ui.hasOwnProperty('CFE_mapping') && Object.keys(ui.CFE_mapping).length > 0 && !self.$scope.group) {
                self.groupsService.get(self.$scope.groupId)
                    .then(self.handleGroupLoading)
                    .catch(self.handleGroupLoadingError);

                let attrs = {};
                for (const property in ui.CFE_mapping) {
                    attrs[ui.CFE_mapping[property].label] = ui.CFE_mapping[property];
                }
                self.$scope.inventoryAttributes = attrs;
            }
        }, true);

        self.$scope.$watch('SQL', function (SQL) {
            if (self.$scope.hasOwnProperty('SqlOriginal')) {
                self.$scope.isFiltersChanged = self.isFiltersChanged(SQL, self.$scope.SqlOriginal);
            }
        }, true);

        self.$scope.$on('INV_FILTER_CHANGED', () => this.$scope.isFiltersChanged = true)

        self.$scope.$on('paginatorChange', function () {
            self.loadInventoryTable(false);
        });
    },

    isFiltersChanged: function (current, origin) {
        // check if filter have same amount of conditions
        if (Object.keys(current.filters).length !== Object.keys(origin.filters).length) {
            return true;
        }

        // check if filters conditions are equal
        for (const indx in origin.filters) {
            const currentFilter = current.filters[indx];
            const originalFilter = origin.filters[indx];

            if (!currentFilter || currentFilter.value != originalFilter.value || currentFilter.condition != originalFilter.condition) {
                return true;
            }
        }

        return (
            Object.values(current.entriesFilter.excludes).sort().toString() !== Object.values(origin.entriesFilter.excludes).sort().toString() ||
            Object.values(current.entriesFilter.includes).sort().toString() !== Object.values(origin.entriesFilter.includes).sort().toString()
        );
    },

    cancelFilterChanges: function () {
        this.$scope.SQL = angular.copy(this.$scope.SqlOriginal);
    },

    clearAllFilters: function () {
        this.$scope.SQL = {
            filters: [],
            entriesFilter: {includes: {}, excludes: {}}
        };
    },

    saveGroup: function () {
        const data = {
            filter: {
                filter: this.inventoryFilterService.processFilters(this.$scope.SQL.filters),
                hostFilter: this.inventoryFilterService.processEntriesFilters(this.$scope.SQL),
                hostContextInclude: this.inventoryFilterService.processClassFilters(this.$scope.SQL.filters),
            }
        }
        common.globalSpinner.show();
        this.groupsService.update(this.$scope.groupId, data).then(
            () => {
                notify.success('Changes saved.');
                this.$scope.isFiltersChanged = false;
                this.groupsService.get(this.$scope.groupId).then((response) => this.$scope.group = response.data);
                common.globalSpinner.hide();
            },
            (error) => {
                notify.error(error.data);
                common.globalSpinner.hide();
            })
    },

    saveGroupTitleFn: async function () {
        const deferred = this.$q.defer();
        try {
            await this.groupsService.update(this.$scope.groupId, {name: this.$scope.data.groupName});
            deferred.resolve();
        } catch (e) {
            deferred.reject(e.data)
        }

        return deferred.promise;
    },

    openInventoryReport: function () {
        const filters = JSON.stringify({
            filter: this.inventoryFilterService.processFilters(this.$scope.SQL.filters),
            hostFilter: this.inventoryFilterService.processEntriesFilters(this.$scope.SQL),
            hostContextInclude: this.inventoryFilterService.processClassFilters(this.$scope.SQL.filters),
        });
        const columns = this.defaultColumns.join(',')
        window.location.href = encodeURI(`/reports/inventory?columns=${columns}&group_filters=${filters}`);
    },

    sortReorder: function (col, e) {
        var self = this;
        angular.forEach(self.$scope.VIEW.tablehead, function (el) {
            if (el.nameToSort === col) {
                el.sort = el.sort > 0 ? -1 : 1;
                self.$scope.VIEW.sortColumn = el.name;
                self.$scope.VIEW.sortDescending = el.sort > 0 ? 0 : 1;
            } else {
                el.sort = null;
            }
        });

        if (self.$scope.VIEW.sortColumn !== undefined && self.$scope.VIEW.sortColumn !== '') {
            self.loadInventoryTable(false);
        }
    },

    loadInventoryTable: function (reInitViewParams = true) {
        let self = this;
        self.runQuery().then(response => {
            self.$scope.inventoryTableData = response.data;
            if (reInitViewParams) {
                self.$scope.paginator.paginationReset();
                self.initVIEWParams();
                angular.forEach(self.$scope.inventoryTableData.header, function (field, key) {
                    var tmp = {};
                    tmp.name = field.columnName;
                    tmp.type = self.$scope.inventoryAttributes[field.columnName] !== undefined ?
                        self.$scope.inventoryAttributes[field.columnName].type :
                        field.columnType;

                    tmp.sort = 0;
                    tmp.fieldIndex = key;
                    tmp.nameToSort = tmp.name + '_' + key;
                    self.$scope.VIEW.tablehead.push(tmp);
                });

                self.$scope.VIEW.rowCount = self.$scope.inventoryTableData.rowCount;
                self.$scope.paginator.refreshPaginator(self.$scope.VIEW.rowCount);
            }

            self.$scope.VIEW.rows = self.$scope.inventoryTableData.rows;
        })
    },

    _getSort: function () {
        var self = this,
            sort = self.$scope.VIEW.sortColumn || '';

        if (sort !== '' && !self.$scope.VIEW.sortDescending) {
            sort = '-' + sort;
        }
        return sort;
    },

    loadWidget: function () {
        this.inventoryService.getInventoryStats({
            type: 'pie',
            attributeName: 'CFEngine version',
            filters: this.$scope.group.filter
        }).then(chartData => {
            this.$scope.versions = Object.keys(chartData.data);
        })
        this.inventoryService.getInventoryStats({
            type: 'pie',
            attributeName: 'OS',
            filters: this.$scope.group.filter
        }).then(chartData => {
            let config = (new PieWidget({chartType: 'pie', inventoryAttribute: 'OS'}, chartData)).getConfig();
            config.plotOptions.pie.center = ['15%', '55%'];
            config.plotOptions.pie.size = '128px';
            config.series[0].innerSize = '70%';
            config.legend.itemWidth = 226;
            this.$scope.widget.config = config;
            this.$scope.os = Object.keys(chartData.data);
        })
    },

    runQuery: function () {
        let self = this;

        self.$scope.SQL.hostcontexts = self.$scope.hostcontexts || '';
        self.$scope.SQL.excludedHosts = self.$scope.excludedHosts || '';

        let contextIncludes = (self.$scope.SQL.hostcontexts && self.$scope.SQL.hostcontexts.includes !== undefined ? self.$scope.SQL.hostcontexts.includes : []);
        const params = {
            sort: self._getSort(),
            select: self.defaultColumns,
            filter: self.inventoryFilterService.processFilters(self.$scope.SQL.filters),
            hostFilter: self.inventoryFilterService.processEntriesFilters(self.$scope.SQL),
            limit: self.$scope.paginator.rowsPerPage,
            start: self.$scope.paginator.skip,
            showSQL: true,
            hostContextInclude: [...contextIncludes, ...self.inventoryFilterService.processClassFilters(self.$scope.SQL.filters)],
            hostContextExclude: (self.$scope.SQL.excludedHosts && self.$scope.SQL.excludedHosts.excludes !== undefined ? self.$scope.SQL.excludedHosts.excludes : []),
        };

        common.globalSpinner.show();
        return self.inventoryDataService.getData(params).then(
            function (result) {
                common.globalSpinner.hide();
                return result;
            },
            function () {
                notify.error('Error encountered. Please view server logs for more detailed information.');
                common.globalSpinner.hide();
            }
        );
    },

    initVIEWParams: function () {
        var self = this;
        self.$scope.VIEW = {};

        self.$scope.VIEW.sortColumn = '';
        self.$scope.VIEW.sortDescending = 0;
        self.$scope.VIEW.tablehead = [];
    },
    initSQLParams: function () {
        this.$scope.SQL = {
            filters: [],
            entriesFilter: {includes: {}, excludes: {}}
        };
    },
});
