/* Copyright CloudLinux Zug GmbH 2010-2017 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 */

import { Component, AfterViewInit, ViewChild, ChangeDetectorRef } from '@angular/core';
import { BaseComponent } from './utils/base_component';
import * as common from './common';
import { Column, ColumnProperties } from './utils/column';
import { StatsRepo } from './repository/stats_repo';
import { AppState } from './app.service';
import { Helper } from './utils/helper';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { ModalStats } from './utils/modal_stats';
import { User } from '../app/model/user';
import { UserEditActions } from './utils/user_actions';
import { UsersRepo } from './repository/users_repo';
import { ViewModes } from '../app/services/view_modes';
import { ModalLimitsUser } from './utils/modal_limits_user';
import { LoaderSelector } from './utils/loader';

declare const panelName: any;

interface IExtendedColumnProperties extends ColumnProperties {
  format?: string;
}

@Component({
    template: require('./../templates/historical.component.html'),
    styles: [
        require('../styles/historical.component.less'),
    ],
    providers: [StatsRepo, UsersRepo, UserEditActions, ViewModes]
})
export class HistoricalComponent extends BaseComponent implements AfterViewInit {
    loaderSelector = new LoaderSelector('.historical_component');
    data: any;
    statRows: any[] = [];
    topRows: TopRow[] = [];
    statColumns: Column[] = [];
    topColumns: Column[] = [];
    chart: SafeHtml;

    _usePeriod: string = common.defaultTimeframe;
    availableTimeframe = common.historicalAvailableTimeframe;

    @ViewChild(ModalStats) modalStats: ModalStats;
    @ViewChild(ModalLimitsUser) modalLimits: ModalLimitsUser;

    mapDescriptions = [
        {
            title: 'SPEED Usage',
            id: 'cpu',
            format: 'percents'
        }, {
            title: 'I/O Usage',
            id: 'io',
            format: 'byteinsec'
        }, {
            title: 'IOPS',
            id: 'iops',
            format: ''
        }, {
            title: 'NPROC',
            id: 'nproc',
            format: ''
        }, {
            title: 'Entry Processes',
            id: 'ep',
            format: ''
        }, {
            title: 'Physical Memory Usage',
            id: 'pmem',
            format: 'bytes'
        }
    ];

    possibleTopColumns: IExtendedColumnProperties[] = [
        {
            name: 'username',
            descr: 'Username',
            convertToFormat: 'string',
            format: ''
        }, {
            name: 'domain',
            descr: 'Domain',
            convertToFormat: 'string',
            format: ''
        }, {
            name: 'usage_cpu_lve',
            descr: 'Speed',
            convertToFormat: 'number',
            format: 'percents'
        }, {
            name: 'usage_pmem_lve',
            descr: 'MEM',
            convertToFormat: 'byte-amount',
            format: 'bytes'
        }, {
            name: 'usage_io_lve',
            descr: 'IO',
            convertToFormat: 'byte-amount',
            format: 'byteinsec'
        }, {
            name: 'usage_iops_lve',
            descr: 'IOPS',
            convertToFormat: 'number',
            format: ''
        }, {
            name: 'usage_ep_lve',
            descr: 'EP',
            convertToFormat: 'number',
            format: ''
        }, {
            name: 'usage_nproc_lve',
            descr: 'NPROC',
            convertToFormat: 'number',
            format: ''
        }, {
            name: 'faults',
            descr: 'Faults',
            convertToFormat: 'number',
        }
    ];

    constructor(public appState: AppState,
                private statsRepo: StatsRepo,
                private _sanitizer: DomSanitizer,
                private usersRepo: UsersRepo,
                private userEditActions: UserEditActions,
                private changeDetector: ChangeDetectorRef) {
        super();
        this.statColumns = [
            new Column({
                name: 'description',
                descr: 'Description',
                convertToFormat: 'string'
            }),
            new Column({
                name: 'usage',
                descr: 'Usage',
                convertToFormat: 'string'
            }).sortableDisable(),
            new Column({
                name: 'limit',
                descr: 'Limit',
                convertToFormat: 'string'
            }).sortableDisable(),
            new Column({
                name: 'fault',
                descr: 'Fault',
                convertToFormat: 'number'
            })
        ];
        this.topColumns = this.getTopColumns();
    }

    get usePeriod() {
        return this._usePeriod;
    }

    set usePeriod(val) {
        this._usePeriod = val;
        this.load();
    }

    ngAfterViewInit(){
        this.load();
    }

    load() {
        this.loading = true;
        this.chart = null;
        this.changeDetector.detectChanges();
        this.getStatistic().then((data: any) => {
            let row = data.resellers.find((reseller) =>
                reseller.name === this.appState.get('userName'));
            if (row) {
                this.statRows = this.parseStats(row);
                this.statsRepo.chart(row.id, {
                    'format': 'svg',
                    'period': this.usePeriod
                }).then((data) => {
                    this.chart = this._sanitizer.bypassSecurityTrustHtml(data.chart);
                    this.loading = false;
                    this.changeDetector.detectChanges();
                });
            } else {
                this.statRows = [];
                this.loading = false;
            }
            this.topRows = this.parseTopStats(data);
        }).catch(() => {
            this.loading = false;
        });
    }

    getStatistic() {
        return new Promise((resolve, reject) => {
            this.statsRepo.getStatistics({
                'period': this.usePeriod,
                'order-by': 'any_faults'
            }).then((data) => {
                if (data.users){
                    resolve(data);
                } else {
                    reject(data);
                }
            }).catch(reject);
        });
    }

    findResellerStat(data) {
        for (let row of data) {
            if (row.name === this.appState.get('userName')) return row;
        }
        return null;
    }

    parseStats(row) {
        return this.mapDescriptions.map((item) => {
            let getValue = (type, fieldId, format) => {
                let value = row[type][fieldId]['lve'];
                return Helper.reformatValue(value, format) || {value: '0' };
            };
            return {
                'description': item.title,
                'usage': getValue('usage', item.id, item.format),
                'limit': getValue('limits', item.id, item.format),
                'fault': getValue('faults', item.id, '')
            };
        });
    }

  parseTopStats(data) {
      const showFaults = [
          ['Cpu', 'faults_cpu_lve'],
          ['PMEM', 'faults_pmem_lve'],
          ['EP', 'faults_ep_lve'],
          ['IO', 'faults_io_lve'],
          ['IOPS', 'faults_iops_lve'],
          ['NPROC', 'faults_nproc_lve']
      ];

        let users = data.users.slice(0, 5);

        let rows = [];
        users.forEach((user) => {
            let row = new TopRow(user.id);
            this.possibleTopColumns.forEach((column) => {
                let value = 0;
                if (column.name === 'faults') {
                    let faultsList = showFaults.map((item) => {
                    let val = Helper.getValueFromObjectRecursively(user, item[1]);
                    value += val;
                    return `${item[0]}: ${val}`;
                    });
                    row.tooltips['faults'] = faultsList.join('<br>');
                } else {
                    value = Helper.getValueFromObjectRecursively(user, column.name);
                }
                row[column.name] =  Helper.reformatValue(value, column.format) || { value: '0' };
            });
            rows.push(row);
        });
        return rows;
    }


    getTopColumns(): Array<Column> {
        let columns = this.possibleTopColumns.map((column) => new Column(column));

        columns.push(new Column({
            name: 'actions',
            descr: 'Actions',
            convertToFormat: 'string'
        }).sortableDisable());

        return columns;
    }

    edit(topRow: TopRow) {
        this.loading = true;
        this.usersRepo.loadUser(topRow.userId).then(({user, response}) => {
            this.userEditActions.globalCageFsStatus = (response.cageFS === 'enabled');
            this.userEditActions.globalMySqlGov = (response.mySqlGov === 'enabled');
            topRow.user = user;
            this.modalLimits.loadEditing(user, this.userEditActions);
            this.loading = false;
            this.modalLimits.show();
        }).catch(() => {
            this.loading = false;
        });
    }

    showHistory(topRow) {
        this.loading = true;
        this.modalStats.loadHistory(topRow.userId, true, this.usePeriod).then(
        () => {
            this.loading = false;
        }
        );
    }

    actionClicked(event) {
        switch(event.action) {
            case 'edit':
                this.edit(event.row);
                break;
            case 'history':
                this.showHistory(event.row);
        }
    }

}

class TopRow {
    public tooltips: any = {};
    public hasEdit: boolean = true;
    public hasHistory: boolean = true;
    public user: User = null;

    constructor (public userId: number) {}

    get loadingStage(): boolean {
        if (this.user) {
            return this.user.loadingStage;
        }
        return false;
    }
}
