/*
 * 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.
 */

import { Component, OnInit, Inject, ChangeDetectorRef } from '@angular/core';
import {FormGroup, FormBuilder, Validators} from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';

import { ComputationalResourceModel } from './computational-resource-create.model';
import { UserResourceService } from '../../../core/services';
import { HTTP_STATUS_CODES, PATTERNS, CheckUtils, SortUtils, HelpUtils } from '../../../core/util';

import { DICTIONARY } from '../../../../dictionary/global.dictionary';
import { CLUSTER_CONFIGURATION } from './cluster-configuration-templates';

@Component({
  selector: 'computational-resource-create-dialog',
  templateUrl: 'computational-resource-create-dialog.component.html',
  styleUrls: ['./computational-resource-create-dialog.component.scss']
})

export class ComputationalResourceCreateDialogComponent implements OnInit {
  readonly PROVIDER = this.data.notebook.cloud_provider;
  readonly DICTIONARY = DICTIONARY;
  readonly CLUSTER_CONFIGURATION = CLUSTER_CONFIGURATION;
  readonly CheckUtils = CheckUtils;

  notebook_instance: any;
  resourcesList: any;
  clusterTypes = [];
  userComputations = [];
  projectComputations = [];
  selectedImage: any;
  spotInstance: boolean = true;
  maxClusterNameLength: number = 14;
  loading: boolean = false;

  public minInstanceNumber: number;
  public maxInstanceNumber: number;
  public minPreemptibleInstanceNumber: number;
  public maxPreemptibleInstanceNumber: number;
  public minSpotPrice: number = 0;
  public maxSpotPrice: number = 0;
  public resourceForm: FormGroup;
  public gpuCount: Array<number> = [1, 2, 4];
  public isSelected = {
    preemptible: false,
    gpu: false,
    spotInstances: false,
    configuration: false,
  };
  public sortGpuTypes = HelpUtils.sortGpuTypes;
  public addSizeToGpuType = HelpUtils.addSizeToGpuType;

  constructor(
    @Inject(MAT_DIALOG_DATA) public data: any,
    public toastr: ToastrService,
    public dialogRef: MatDialogRef<ComputationalResourceCreateDialogComponent>,
    private userResourceService: UserResourceService,
    private model: ComputationalResourceModel,
    private _fb: FormBuilder,
    private _ref: ChangeDetectorRef,
  ) { }

  ngOnInit() {
    this.loading = true;
    this.notebook_instance = this.data.notebook;
    this.resourcesList = this.data.full_list;
    this.initFormModel();
    this.getTemplates(this.notebook_instance.project, this.notebook_instance.endpoint, this.notebook_instance.cloud_provider);
  }

  public selectImage($event) {
    this.selectedImage = $event;
    this.filterShapes();
    this.getComputationalResourceLimits();

    if ($event.templates && $event.templates.length) {
      this.resourceForm.controls['version'].setValue($event.templates[0].version);
    }
  }

  public selectSpotInstances(): void {
    if (this.isSelected.spotInstances) {
      this.spotInstance = true;
      this.resourceForm.controls['instance_price'].setValue(50);
    } else {
      this.spotInstance = false;
      this.resourceForm.controls['instance_price'].setValue(0);
    }
  }

  public selectPreemptibleNodes(addPreemptible) {
    if (addPreemptible) {
      this.resourceForm.controls['preemptible_instance_number'].setValue(this.minPreemptibleInstanceNumber);
    }
  }

  public selectConfiguration() {
    if (this.isSelected.configuration) {
      const template = (this.selectedImage.image === 'docker.datalab-dataengine-service')
        ? CLUSTER_CONFIGURATION.EMR
        : CLUSTER_CONFIGURATION.SPARK;
      this.resourceForm.controls['configuration_parameters'].setValue(JSON.stringify(template, undefined, 2));
    } else {
      this.resourceForm.controls['configuration_parameters'].setValue('');
    }
  }

  public preemptibleCounter($event, action): void {
    $event.preventDefault();

    const value = this.resourceForm.controls['preemptible_instance_number'].value;
    const newValue = (action === 'increment' ? Number(value) + 1 : Number(value) - 1);
    this.resourceForm.controls.preemptible_instance_number.setValue(newValue);
  }

  public isAvailableSpots(): boolean {
    if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
      return !!Object.keys(this.filterAvailableSpots()).length;
    }

    return false;
  }

  public createComputationalResource(data) {
    this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance,
      this.spotInstance, this.PROVIDER.toLowerCase(), this.isSelected.gpu)
      .subscribe(
        (response: any) => {
          if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close(true);
        }, 
        error => this.toastr.error(error.message, 'Oops!')
      );
  }

  private initFormModel(): void {
    this.resourceForm = this._fb.group({
      template_name: ['', [Validators.required]],
      version: [''],
      shape_master: ['', Validators.required],
      shape_slave: [''],
      cluster_alias_name: ['', [
        Validators.required, Validators.pattern(PATTERNS.namePattern),
        Validators.maxLength(this.maxClusterNameLength),
      this.checkDuplication.bind(this)
      ]],
      instance_number: ['', [Validators.required, Validators.pattern(PATTERNS.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
      preemptible_instance_number: [0,
        Validators.compose([Validators.pattern(PATTERNS.integerRegex),
        this.validPreemptibleRange.bind(this)])],
      instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
      configuration_parameters: ['', [this.validConfiguration.bind(this)]],
      custom_tag: [this.notebook_instance.tags.custom_tag],
      master_GPU_type: [''],
      slave_GPU_type: [''],
      master_GPU_count: [''],
      slave_GPU_count: [''],
    });
  }

  private shapePlaceholder(resourceShapes, byField: string) {
    for (const index in resourceShapes) return resourceShapes[index][0][byField];
  }

  private getComputationalResourceLimits(): void {
    if (this.selectedImage && this.selectedImage.image) {
      const activeImage = DICTIONARY[this.PROVIDER][this.selectedImage.image];

      this.minInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_min];
      this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max];

      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
        this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max] - 1;
        this.minPreemptibleInstanceNumber = this.selectedImage.limits.min_dataproc_preemptible_instance_count;
      }

      if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
        this.minSpotPrice = this.selectedImage.limits.min_emr_spot_instance_bid_pct;
        this.maxSpotPrice = this.selectedImage.limits.max_emr_spot_instance_bid_pct;

        this.isSelected.spotInstances = true;
        this.selectSpotInstances();
      }

      this.resourceForm.controls['instance_number'].setValue(this.minInstanceNumber);
      this.resourceForm.controls['preemptible_instance_number'].setValue(this.minPreemptibleInstanceNumber);
    }
  }

  //  Validation

  private validInstanceNumberRange(control) {
    if (control && control.value) {
      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
        this.validPreemptibleNumberRange();
        return control.value >= this.minInstanceNumber && control.value <= this.maxInstanceNumber ? null : { valid: false };
      } else {
        return control.value >= this.minInstanceNumber && control.value <= this.maxInstanceNumber ? null : { valid: false };
      }
    }
  }

  private validPreemptibleRange(control) {
    if (this.isSelected.preemptible) {
      return this.isSelected.preemptible
        ? (control.value !== null
          && control.value >= this.minPreemptibleInstanceNumber
          && control.value <= this.maxPreemptibleInstanceNumber ? null : { valid: false })
        : control.value;
    }
  }

  private validPreemptibleNumberRange() {
    const instance_value = this.resourceForm.controls['instance_number'].value;
    this.maxPreemptibleInstanceNumber = Math.max((this.maxInstanceNumber - instance_value), 0);

    const value = this.resourceForm.controls['preemptible_instance_number'].value;
    if (value !== null && value >= this.minPreemptibleInstanceNumber && value <= this.maxPreemptibleInstanceNumber) {
      this.resourceForm.controls['preemptible_instance_number'].setErrors(null);
    } else {
      this.resourceForm.controls['preemptible_instance_number'].setErrors({ valid: false });
    }
  }

  private validInstanceSpotRange(control) {
    if (this.isSelected.spotInstances) {
      return this.isSelected.spotInstances
        ? (control.value >= this.minSpotPrice && control.value <= this.maxSpotPrice ? null : { valid: false })
        : control.value;
    }
  }

  private validConfiguration(control) {
    if (this.isSelected.configuration) {
      return this.isSelected.configuration 
        ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
        : null;
    }
  }

  private checkDuplication(control) {
    if (this.containsComputationalResource(control.value, this.userComputations)) {
      return { 'user-duplication': true };
    }

    if (this.containsComputationalResource(control.value, this.projectComputations)) {
      return { 'other-user-duplication': true };
    }
  }

  private getTemplates(project, endpoint, provider) {
    this.userResourceService.getComputationalTemplates(project, endpoint, provider).subscribe(
      clusterTypes => {
        this.clusterTypes = clusterTypes.templates;
        this.userComputations = clusterTypes.user_computations;
        this.projectComputations = clusterTypes.project_computations;

        this.clusterTypes.forEach((cluster, index) => this.clusterTypes[index].computation_resources_shapes =
          SortUtils.shapesSort(cluster.computation_resources_shapes));
        this.selectedImage = this.clusterTypes[0];
        if (this.selectedImage) {
          this._ref.detectChanges();
          this.filterShapes();
          this.resourceForm.get('template_name').setValue(this.selectedImage.template_name);
          this.getComputationalResourceLimits();
        }

        this.loading = false;
      }, () => this.loading = false);
  }

  private filterShapes(): void {
    const allowed: any = ['GPU optimized'];
    let filtered;

    const reduceShapes = (obj, key) => {
      obj[key] = this.selectedImage.computation_resources_shapes[key];
      return obj;
    };

    const filteredShapeKeys = Object.keys(
      SortUtils.shapesSort(this.selectedImage.computation_resources_shapes));

    const filterShapes = (filter) => filteredShapeKeys
      .filter(filter)
      .reduce(reduceShapes, {});

    if (this.notebook_instance.template_name.toLowerCase().indexOf('tensorflow') !== -1
      || this.notebook_instance.template_name.toLowerCase().indexOf('deep learning') !== -1
    ) {
      filtered = filterShapes(key => allowed.includes(key));
      if (this.PROVIDER !== 'azure') {
        const images = this.clusterTypes.filter(image => image.image === 'docker.datalab-dataengine');
        this.clusterTypes = images;
        this.selectedImage = this.clusterTypes[0];
      }
    } else if (this.notebook_instance.template_name.toLowerCase().indexOf('jupyter notebook') !== -1 &&
      this.selectedImage.image === 'docker.datalab-dataengine-service' && this.notebook_instance.cloud_provider !== 'gcp') {
      filtered = filterShapes(v => v);
    } else {
      filtered = filterShapes(key => !(allowed.includes(key)));
    }
    this.selectedImage.computation_resources_shapes = filtered;
  }

  private filterAvailableSpots() {
    const filtered = JSON.parse(JSON.stringify(this.selectedImage.computation_resources_shapes));
    for (const item in this.selectedImage.computation_resources_shapes) {
      filtered[item] = filtered[item].filter(el => el.spot);
      if (filtered[item].length <= 0) {
        delete filtered[item];
      }
    }
    return filtered;
  }

  private containsComputationalResource(conputational_resource_name: string, existNames: Array<string>): boolean {
    if (conputational_resource_name) {
      return existNames.some(resource =>
        CheckUtils.delimitersFiltering(conputational_resource_name) === CheckUtils.delimitersFiltering(resource));
    }
  }

  public addAdditionalParams(block: string) {
    this.isSelected[block] = !this.isSelected[block];

    if (block === 'configuration') {
      this.selectConfiguration();
    }

    if (block === 'gpu') {
      const controls = ['master_GPU_type', 'master_GPU_count', 'slave_GPU_type', 'slave_GPU_count'];
      if (!this.isSelected.gpu) {
        this.clearGpuType('master');
        this.clearGpuType('slave');
        controls.forEach(control => {
          this.resourceForm.controls[control].clearValidators();
          this.resourceForm.controls[control].updateValueAndValidity();
        });

      } else {
        controls.forEach(control => {
          this.resourceForm.controls[control].setValidators([Validators.required]);
          this.resourceForm.controls[control].updateValueAndValidity();
        });
      }
    }
  }

  public clearGpuType(type) {
    if (type === 'master') {
      this.resourceForm.controls['master_GPU_type'].setValue('');
      this.resourceForm.controls['master_GPU_count'].setValue('');
    } else {
      this.resourceForm.controls['slave_GPU_type'].setValue('');
      this.resourceForm.controls['slave_GPU_count'].setValue('');
    }
  }
}
