/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/* tslint:disable:no-empty */

import {Component, Input, OnInit} from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { ToastrService } from 'ngx-toastr';
import { MatDialog } from '@angular/material/dialog';

import { UserResourceService } from '../../core/services';

import { ExploratoryModel, Exploratory } from './resources-grid.model';
import { FilterConfigurationModel } from './filter-configuration.model';
import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
import { ConfirmationDialogType } from '../../shared';
import { SortUtils, CheckUtils } from '../../core/util';
import { DetailDialogComponent } from '../exploratory/detail-dialog';
import { AmiCreateDialogComponent } from '../exploratory/ami-create-dialog';
import { InstallLibrariesComponent } from '../exploratory/install-libraries';
import { ComputationalResourceCreateDialogComponent } from '../computational/computational-resource-create-dialog/computational-resource-create-dialog.component';
import { CostDetailsDialogComponent } from '../exploratory/cost-details-dialog';
import { ConfirmationDialogComponent } from '../../shared/modal-dialog/confirmation-dialog';
import { SchedulerComponent } from '../scheduler';

import { DICTIONARY } from '../../../dictionary/global.dictionary';
import {ProgressBarService} from '../../core/services/progress-bar.service';
import {ComputationModel} from '../computational/computational-resource.model';
import {NotebookModel} from '../exploratory/notebook.model';




@Component({
  selector: 'resources-grid',
  templateUrl: 'resources-grid.component.html',
  styleUrls: ['./resources-grid.component.scss'],
  animations: [
    trigger('detailExpand', [
      state('collapsed', style({ height: '0px', minHeight: '0' })),
      state('expanded', style({ height: '*' })),
      transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ]),
  ],
})

export class ResourcesGridComponent implements OnInit {
  readonly DICTIONARY = DICTIONARY;

  @Input() projects: Array<any>;

  environments: Exploratory[];

  collapseFilterRow: boolean = false;
  filtering: boolean = false;
  activeFiltering: boolean = false;
  activeProject: any;
  healthStatus: GeneralEnvironmentStatus;

  filteredEnvironments: Exploratory[] = [];
  filterConfiguration: FilterConfigurationModel = new FilterConfigurationModel('', [], [], [], '', '');
  filterForm: FilterConfigurationModel = new FilterConfigurationModel('', [], [], [], '', '');

  public filteringColumns: Array<any> = [
    { title: 'Environment name', name: 'name', class: 'name-col', filter_class: 'name-filter', filtering: true },
    { title: 'Status', name: 'statuses', class: 'status-col', filter_class: 'status-filter', filtering: true },
    { title: 'Instance size', name: 'shapes', class: 'shape-col', filter_class: 'shape-filter', filtering: true },
    { title: 'Tags', name: 'tag', class: 'tag-col', filter_class: 'tag-filter', filtering: false },
    { title: 'Computational resource', name: 'resources', class: 'resources-col', filter_class: 'resource-filter', filtering: true },
    { title: 'Cost', name: 'cost', class: 'cost-col', filter_class: 'cost-filter', filtering: false },
    { title: '', name: 'actions', class: 'actions-col', filter_class: 'action-filter', filtering: false }
  ];

  public displayedColumns: string[] = this.filteringColumns.map(item => item.name);
  public displayedFilterColumns: string[] = this.filteringColumns.map(item => item.filter_class);


  constructor(
    public toastr: ToastrService,
    private userResourceService: UserResourceService,
    private dialog: MatDialog,
    private progressBarService: ProgressBarService,
  ) { }

  ngOnInit(): void {
    this.buildGrid();
  }

  public buildGrid(): void {
    setTimeout(() => {this.progressBarService.startProgressBar(); } , 0);
    this.userResourceService.getUserProvisionedResources()
      .subscribe((result: any) => {
        this.environments = ExploratoryModel.loadEnvironments(result);
        this.getDefaultFilterConfiguration();
        (this.environments.length) ? this.getUserPreferences() : this.filteredEnvironments = [];
        this.healthStatus && !this.healthStatus.billingEnabled && this.modifyGrid();
        this.progressBarService.stopProgressBar();
      }, () => this.progressBarService.stopProgressBar());
  }

  public toggleFilterRow(): void {
    this.collapseFilterRow = !this.collapseFilterRow;
  }

  public onUpdate($event) {
    this.filterForm[$event.type] = $event.model;
  }

  public selectActiveProject(project = '') {
    this.filterForm.project = project;
    this.applyFilter_btnClick(this.filterForm);
  }

  public showActiveInstances(): void {
    this.filterForm = this.loadUserPreferences(this.filterActiveInstances());
    this.applyFilter_btnClick(this.filterForm);
    this.buildGrid();
  }

  public containsNotebook(notebook_name: string, envoirmentNames: Array<string>): boolean {
    if (notebook_name && envoirmentNames.length ) {
        return envoirmentNames
          .some(item => CheckUtils.delimitersFiltering(notebook_name) === CheckUtils.delimitersFiltering(item));
      }
      return false;
   }


  public isResourcesInProgress(notebook) {
    const env = this.getResourceByName(notebook.name, notebook.project);

    if (env && env.resources.length) {
      return env.resources.filter(item => (item.status !== 'failed' && item.status !== 'terminated'
        && item.status !== 'running' && item.status !== 'stopped')).length > 0;
    }
    return false;
  }

  public isEdgeNodeStopped(resource) {
    const currProject = this.projects.filter(proj => proj.name === resource.project);
    const currEdgenodeStatus =  currProject[0].endpoints.filter(node => node.name === resource.endpoint)[0].status;
    return currEdgenodeStatus === 'STOPPED' || currEdgenodeStatus === 'STOPPING';
  }

  public filterActiveInstances(): FilterConfigurationModel {
    return (<FilterConfigurationModel | any>Object).assign({}, this.filterConfiguration, {
      statuses: SortUtils.activeStatuses(),
      resources: SortUtils.activeStatuses(),
      type: 'active',
      project: this.activeProject || ''
    });
  }

  public resetFilterConfigurations(): void {
    this.filterForm.resetConfigurations();
    this.updateUserPreferences(this.filterForm);
    this.buildGrid();
  }

  public printDetailEnvironmentModal(data): void {
    this.dialog.open(DetailDialogComponent, { data: data, panelClass: 'modal-lg' })
      .afterClosed().subscribe(() => this.buildGrid());
  }

  public printCostDetails(data): void {
    this.dialog.open(CostDetailsDialogComponent, { data: data, panelClass: 'modal-xl' })
      .afterClosed().subscribe(() => this.buildGrid());
  }

  public exploratoryAction(data, action: string) {
    const resource = this.getResourceByName(data.name, data.project);

    if (action === 'deploy') {
      this.dialog.open(ComputationalResourceCreateDialogComponent, { data: { notebook: resource, full_list: this.environments }, panelClass: 'modal-xxl' })
        .afterClosed().subscribe(() => this.buildGrid());
    } else if (action === 'run') {
      this.userResourceService
        .runExploratoryEnvironment({ notebook_instance_name: data.name, project_name: data.project })
        .subscribe(
          () => this.buildGrid(),
          error => this.toastr.error(error.message || 'Exploratory starting failed!', 'Oops!'));
    } else if (action === 'stop') {
      this.dialog.open(ConfirmationDialogComponent, { data: { notebook: data, type: ConfirmationDialogType.StopExploratory }, panelClass: 'modal-sm' })
        .afterClosed().subscribe(() => this.buildGrid());
    } else if (action === 'terminate') {
      this.dialog.open(ConfirmationDialogComponent, { data:
          { notebook: data, type: ConfirmationDialogType.TerminateExploratory }, panelClass: 'modal-sm' })
        .afterClosed().subscribe(() => this.buildGrid());
    } else if (action === 'install') {
      this.dialog.open(InstallLibrariesComponent, { data: data, panelClass: 'modal-fullscreen' })
        .afterClosed().subscribe(() => this.buildGrid());
    } else if (action === 'schedule') {
      this.dialog.open(SchedulerComponent, { data: { notebook: data, type: 'EXPLORATORY' }, panelClass: 'modal-xl-s' })
        .afterClosed().subscribe(() => this.buildGrid());
    } else if (action === 'ami') {
      this.dialog.open(AmiCreateDialogComponent, { data: data, panelClass: 'modal-sm' })

        .afterClosed().subscribe(() => this.buildGrid());
    }
  }


  // PRIVATE
  private getResourceByName(notebook_name: string, project_name: string) {
    return this.getEnvironmentsListCopy().filter(environments => environments.project === project_name)
      .map(env => env.exploratory.find(({ name }) => name === notebook_name))
      .filter(name => !!name)[0];
  }

  private getEnvironmentsListCopy() {
    return this.environments.map(env => JSON.parse(JSON.stringify(env)));
  }

  private getDefaultFilterConfiguration(): void {
    const data: Exploratory[] = this.environments;
    const shapes = [], statuses = [], resources = [];

    data.filter(elem => elem.exploratory.map((item: any) => {
      if (shapes.indexOf(item.shape) === -1) shapes.push(item.shape);
      if (statuses.indexOf(item.status) === -1) statuses.push(item.status);
      statuses.sort(SortUtils.statusSort);

      item.resources.map((resource: any) => {
        if (resources.indexOf(resource.status) === -1) resources.push(resource.status);
        resources.sort(SortUtils.statusSort);
      });
    }));

    this.filterConfiguration = new FilterConfigurationModel('', statuses, shapes, resources, '', '');
  }

  private applyFilter_btnClick(config: FilterConfigurationModel) {

    let filteredData = this.getEnvironmentsListCopy();

    const containsStatus = (list, selectedItems) => {
      return list.filter((item: any) => { if (selectedItems.indexOf(item.status) !== -1) return item; });
    };

    if (filteredData.length) this.filtering = true;
    if (config) {
      this.activeProject = config.project;
      filteredData = filteredData
        .filter(project => config.project ? project.project === config.project : project)
        .filter(project => {

          project.exploratory = project.exploratory.filter(item => {

            const isName = item.name.toLowerCase().indexOf(config.name.toLowerCase()) !== -1;
            const isStatus = config.statuses.length > 0 ? (config.statuses.indexOf(item.status) !== -1) : (config.type !== 'active');
            const isShape = config.shapes.length > 0 ? (config.shapes.indexOf(item.shape) !== -1) : true;

            const modifiedResources = containsStatus(item.resources, config.resources);
            let isResources = config.resources.length > 0 ? (modifiedResources.length > 0) : true;

            if (config.resources.length > 0 && modifiedResources.length > 0) { item.resources = modifiedResources; }

            if (config.resources.length === 0 && config.type === 'active' ||
              modifiedResources.length >= 0 && config.resources.length > 0 && config.type === 'active') {
              item.resources = modifiedResources;
              isResources = true;
            }

            return isName && isStatus && isShape && isResources;
          });
          return project.exploratory.length > 0;
        });

      this.updateUserPreferences(config);
    }

    let failedNotebooks = NotebookModel.notebook(this.getEnvironmentsListCopy());
    failedNotebooks = SortUtils.flatDeep(failedNotebooks, 1).filter(notebook => notebook.status === 'failed');
    if (this.filteredEnvironments.length && this.activeFiltering) {
      let creatingNotebook = NotebookModel.notebook(this.filteredEnvironments);
      creatingNotebook = SortUtils.flatDeep(creatingNotebook, 1).filter(resourse => resourse.status === 'creating');
      const fail = failedNotebooks
        .filter(v => creatingNotebook
          .some(create => create.project === v.project && create.exploratory === v.exploratory && create.resource === v.resource));
      if (fail.length) {
        this.toastr.error('Creating notebook failed!', 'Oops!');
      }
    }

    let failedResource = ComputationModel.computationRes(this.getEnvironmentsListCopy());
    failedResource = SortUtils.flatDeep(failedResource, 2).filter(resourse => resourse.status === 'failed');
    if (this.filteredEnvironments.length && this.activeFiltering) {
      let creatingResource = ComputationModel.computationRes(this.filteredEnvironments);
      creatingResource = SortUtils.flatDeep(creatingResource, 2).filter(resourse => resourse.status === 'creating');
      const fail = failedResource
        .filter(v => creatingResource
          .some(create => create.project === v.project && create.exploratory === v.exploratory && create.resource === v.resource));
      if (fail.length) {
        this.toastr.error('Creating computation resource failed!', 'Oops!');
      }
    }
    this.filteredEnvironments = filteredData;
  }

  private modifyGrid(): void {
    this.displayedColumns = this.displayedColumns.filter(el => el !== 'cost');
    this.displayedFilterColumns = this.displayedFilterColumns.filter(el => el !== 'cost-filter');
  }

  private aliveStatuses(сonfig): void {
    for (const index in this.filterConfiguration) {
      if (сonfig[index] && сonfig[index] instanceof Array)
        сonfig[index] = сonfig[index].filter(item => this.filterConfiguration[index].includes(item));
    }
    return сonfig;
  }

  isActiveFilter(filterConfig): void {
    this.activeFiltering = false;

    for (const index in filterConfig)
      if (filterConfig[index].length) this.activeFiltering = true;
  }

  private getUserPreferences(): void {
    this.userResourceService.getUserPreferences()
      .subscribe((result: FilterConfigurationModel) => {
        if (result) {
          this.isActiveFilter(result);
          this.filterForm = this.loadUserPreferences(result.type ? this.filterActiveInstances() : this.aliveStatuses(result));
        }
        this.applyFilter_btnClick(result || this.filterForm);
      }, () => this.applyFilter_btnClick(null));
  }

  private loadUserPreferences(config): FilterConfigurationModel {
    return new FilterConfigurationModel(config.name, config.statuses, config.shapes, config.resources, config.type, config.project);
  }

  private updateUserPreferences(filterConfiguration: FilterConfigurationModel): void {
    this.userResourceService.updateUserPreferences(filterConfiguration)
      .subscribe((result) => { },
        (error) => console.log('UPDATE USER PREFERENCES ERROR ', error));
  }
}
