/*
 * 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 } 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 { Project } from '../../../administration/project/project.component';
import { UserResourceService, ProjectService } from '../../../core/services';
import { CheckUtils, SortUtils, HTTP_STATUS_CODES, PATTERNS, HelpUtils } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
import { CLUSTER_CONFIGURATION } from '../../computational/computational-resource-create-dialog/cluster-configuration-templates';
import { tap } from 'rxjs/operators';
import { timer } from 'rxjs';

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

export class ExploratoryEnvironmentCreateComponent implements OnInit {
  readonly DICTIONARY = DICTIONARY;
  public createExploratoryForm: FormGroup;
  public projectExploratories: {};

  projects: Project[] = [];
  templates = [];
  endpoints: Array<String> = [];
  currentTemplate: any;
  shapes = [] || {};
  resourceGrid: any;
  images: Array<any>;
  selectedImage: any;
  maxNotebookLength: number = 14;
  maxCustomTagLength: number = 63;
  public areShapes: boolean;
  public selectedCloud: string = '';
  public gpuCount: Array<number>;
  public gpuTypes: Array<string> = [];
  public addSizeToGpuType = HelpUtils.addSizeToGpuType;

  public additionalParams = {
    configurationNode: false,
    gpu: false,
  };

  constructor(
    @Inject(MAT_DIALOG_DATA) public data: any,
    public toastr: ToastrService,
    public dialogRef: MatDialogRef<ExploratoryEnvironmentCreateComponent>,
    private userResourceService: UserResourceService,
    private _fb: FormBuilder,
    private projectService: ProjectService
  ) {
    this.resourceGrid = data;
  }

  ngOnInit() {
    this.getNamesByProject();
    this.getUserProjects();
    this.initFormModel();
    this.createExploratoryForm.get('project').valueChanges.subscribe(v => {
      if ( this.createExploratoryForm.controls.name.value) {
        this.createExploratoryForm.get('name').updateValueAndValidity();
      }
    });
  }

  public getProjects() {
    this.projectService.getProjectsList().subscribe((projects: any) => this.projects = projects);
  }

  public getUserProjects() {
    this.projectService.getUserProjectsList(true).subscribe((projects: any) => {
      this.projects = projects;
      const activeProject = projects.find(item => item.name === this.resourceGrid.activeProject);
      if (this.resourceGrid.activeProject && activeProject) {
        this.setEndpoints(activeProject);
        this.createExploratoryForm.controls['project'].setValue(activeProject.name);
      }
    });
  }

  public setImage(image) {
    this.selectedImage = image;
    timer(500).subscribe(_ => {
      document.querySelector('#buttons').scrollIntoView({ block: 'center', behavior: 'smooth' });
    });
  }

  public setEndpoints(project) {
    const controls = ['endpoint', 'version', 'shape', 'gpu_type', 'gpu_count'];
    this.resetSelections(controls);
    
    this.endpoints = project.endpoints
      .filter(e => e.status === 'RUNNING')
      .map(e => e.name);
  }

  public resetSelections(controls: Array<string>) {
    if (this.images) this.images = [];
    if (this.selectedCloud) this.selectedCloud = '';
    if (this.additionalParams.gpu) {
      this.additionalParams.gpu = !this.additionalParams.gpu;
      this.createExploratoryForm.controls['gpu_enabled'].setValue(this.additionalParams.gpu);
    }
    this.selectedImage = null;
    this.areShapes = false;
    this.templates = [];
    this.currentTemplate = [];
    controls.forEach(control => {
      this.createExploratoryForm.controls[control].setValue(null);
    });
  }

  public getTemplates(project, endpoint) {
    const controls = ['version', 'shape'];
    this.resetSelections(controls);

    const endpoints = this.data.environments.find(env => env.project === project).endpoints;
    this.selectedCloud = endpoints.find(endp => endp.name === endpoint).cloudProvider.toLowerCase();

    this.userResourceService.getExploratoryTemplates(project, endpoint)
      .pipe(tap(results => {
        results.sort((a, b) =>
          (a.exploratory_environment_versions[0].template_name > b.exploratory_environment_versions[0].template_name) ?
            1 : -1);
      }))
      .subscribe(templates =>  {
        this.templates = templates;
        }
      );
  }

  public getShapes(template) {
    this.selectedImage = null;
    const controls = ['notebook_image_name', 'shape', 'gpu_type', 'gpu_count'];

    controls.forEach(control => {
      this.createExploratoryForm.controls[control].setValue(null);
      if (control !== 'shape') {
        this.createExploratoryForm.controls[control].clearValidators();
        this.createExploratoryForm.controls[control].updateValueAndValidity();
      }
    });

    if (this.additionalParams.gpu) {
      this.additionalParams.gpu = !this.additionalParams.gpu;
      this.createExploratoryForm.controls['gpu_enabled'].setValue(this.additionalParams.gpu);
    }

    if (this.selectedCloud === 'gcp' && template?.image === 'docker.datalab-deeplearning') {
      this.createExploratoryForm.controls['notebook_image_name'].setValidators([Validators.required]);
      this.createExploratoryForm.controls['notebook_image_name'].updateValueAndValidity();
    }
    
    if (this.selectedCloud === 'gcp' && 
        (template?.image === 'docker.datalab-jupyter' ||
        template?.image === 'docker.datalab-deeplearning' ||
        template?.image === 'docker.datalab-tensor')) {
          
      this.gpuTypes = template?.computationGPU ? HelpUtils.sortGpuTypes(template.computationGPU) : [];

      if(template?.image === 'docker.datalab-tensor' || template?.image === 'docker.datalab-deeplearning') {
        this.addGpuFields();
      }
    }

    this.currentTemplate = template;
    const allowed: any = ['GPU optimized'];

    if (template.exploratory_environment_versions[0].template_name.toLowerCase().indexOf('tensorflow') === -1
      && template.exploratory_environment_versions[0].template_name.toLowerCase().indexOf('deeplearning') === -1
      && template.exploratory_environment_versions[0].template_name.toLowerCase().indexOf('deep learning') === -1
      && template.exploratory_environment_versions[0].template_name.toLowerCase().indexOf('data science') === -1
    ) {
      const filtered = Object.keys(
        SortUtils.shapesSort(template.exploratory_environment_shapes))
        .filter(key => !(allowed.includes(key)))
        .reduce((obj, key) => {
          obj[key] = template.exploratory_environment_shapes[key];
          return obj;
        }, {});
      template.exploratory_environment_shapes.computation_resources_shapes = filtered;
      this.shapes = SortUtils.shapesSort(template.exploratory_environment_shapes.computation_resources_shapes);
      this.getImagesList();
    } else {
      this.shapes = SortUtils.shapesSort(template.exploratory_environment_shapes);
      this.getImagesList();
    }
    this.areShapes = !!Object.keys(this.shapes).length;
  }

  public createExploratoryEnvironment(data) {
    const parameters: any = {
      image: this.currentTemplate.image,
      template_name: this.currentTemplate.exploratory_environment_versions[0].template_name
    };

    if (!data.notebook_image_name 
      && this.currentTemplate.image === 'docker.datalab-deeplearning' 
      && this.selectedCloud === 'aws' || this.selectedCloud === 'azure') {
      data.notebook_image_name = this.currentTemplate.exploratory_environment_versions[0].version;
    }

    data.cluster_config = data.cluster_config ? JSON.parse(data.cluster_config) : null;

    this.userResourceService.createExploratoryEnvironment({ ...parameters, ...data }).subscribe((response: any) => {
      if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close();
    }, error => this.toastr.error(error.message || 'Exploratory creation failed!', 'Oops!'));
  }

  public getNamesByProject() {
    this.userResourceService.getProjectByExploratoryEnvironment().subscribe(responce => {
      this.projectExploratories = responce;
    });
  }

  public selectConfiguration() {
    this.additionalParams.configurationNode = !this.additionalParams.configurationNode;
    if (this.additionalParams.configurationNode) {
      const value = (this.additionalParams.configurationNode && this.createExploratoryForm)
        ? JSON.stringify(CLUSTER_CONFIGURATION.SPARK, undefined, 2) : '';
      timer(500).subscribe(_ => {
        document.querySelector('#buttons').scrollIntoView({ block: 'start', behavior: 'smooth' });
      });
      this.createExploratoryForm.controls['cluster_config'].setValue(value);
    }
  }

  public addGpuFields() {
    this.additionalParams.gpu = !this.additionalParams.gpu;
    this.createExploratoryForm.controls['gpu_enabled'].setValue(this.additionalParams.gpu);

    const controls = ['gpu_type', 'gpu_count'];
    if (!this.additionalParams.gpu) {
      controls.forEach(control => {
        this.createExploratoryForm.controls[control].setValue(null);
        this.createExploratoryForm.controls[control].clearValidators();
        this.createExploratoryForm.controls[control].updateValueAndValidity();
      });

    } else {
      controls.forEach(control => {
        this.createExploratoryForm.controls[control].setValidators([Validators.required]);
        this.createExploratoryForm.controls[control].updateValueAndValidity();
      });
      timer(500).subscribe(_ => {
        document.querySelector('#buttons').scrollIntoView({ block: 'center', behavior: 'smooth' });
      });
    }
  }

  public setInstanceSize() {
    const controls = ['gpu_type', 'gpu_count'];
    controls.forEach(control => {
      this.createExploratoryForm.controls[control].setValue(null);
    });
  }

  public setCount(type: any, gpuType: any): void {
    if (gpuType && this.currentTemplate.image === 'docker.datalab-deeplearning') {
      this.additionalParams.gpu = true;
      this.createExploratoryForm.controls['gpu_enabled'].setValue(this.additionalParams.gpu);
      this.createExploratoryForm.controls['gpu_count'].setValidators([Validators.required]);
      this.createExploratoryForm.controls['gpu_count'].updateValueAndValidity();
    }
    // if (type === 'master') {
      this.gpuCount = [1, 2, 4];
    // } else {
    //   const slaveShape = this.resourceForm.controls['shape_slave'].value;
    //   this.slaveGPUcount = HelpUtils.setGPUCount(slaveShape, gpuType);
    // }
  }

  private initFormModel(): void {
    this.createExploratoryForm = this._fb.group({
      project: ['', Validators.required],
      endpoint: ['', Validators.required],
      version: ['', Validators.required],
      notebook_image_name: [''],
      shape: ['', Validators.required],
      name: ['', [
        Validators.required,
        Validators.pattern(PATTERNS.namePattern),
        Validators.maxLength(this.maxNotebookLength),
        this.checkDuplication.bind(this)
      ]],
      cluster_config: ['', [this.validConfiguration.bind(this)]],
      custom_tag: ['', [
        Validators.pattern(PATTERNS.namePattern),
        Validators.maxLength(this.maxCustomTagLength)
      ]],
      gpu_type: [null],
      gpu_count: [null],
      gpu_enabled: [false]
    });
  }

  private getImagesList() {
    this.userResourceService.getUserImages(this.currentTemplate.image, this.createExploratoryForm.controls['project'].value,
      this.createExploratoryForm.controls['endpoint'].value)
      .subscribe(
        (res: any) => {
          this.images = res.filter(el => el.status === 'CREATED');
          
          if(this.selectedCloud === 'gcp' && this.currentTemplate.image === 'docker.datalab-deeplearning') {
            this.currentTemplate.exploratory_environment_images = this.currentTemplate.exploratory_environment_images.map(image => {
              return {name: image['Image family'] ?? image.name, description: image['Description'] ?? image.description}
            });
            this.images.push(...this.currentTemplate.exploratory_environment_images);
          }
        },
        error => this.toastr.error(error.message || 'Images list loading failed!', 'Oops!')
      );
  }

  private checkDuplication(control) {
    if (this.createExploratoryForm
      && this.createExploratoryForm.controls.project.value
      && this.resourceGrid.containsNotebook(control.value, this.projectExploratories[this.createExploratoryForm.controls.project.value]))
      return { duplication: true };
  }

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