/*
 * 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 { Input, Output, Component, EventEmitter } from '@angular/core';

@Component({
  selector: 'multi-level-select-dropdown',
  templateUrl: 'multi-level-select-dropdown.component.html',
  styleUrls: ['multi-level-select-dropdown.component.scss']
})

export class MultiLevelSelectDropdownComponent {

  @Input() items: Array<any>;
  @Input() model: Array<any>;
  @Input() type: string;
  @Output() selectionChange: EventEmitter<{}> = new EventEmitter();

  public isOpenCategory = {
  };

  public isCloudOpen = {

  };

  public labels = {
    COMPUTATIONAL_SHAPE: 'Compute shapes',
    NOTEBOOK_SHAPE: 'Notebook shapes',
    COMPUTATIONAL: 'Compute'
  };

  toggleSelectedOptions($event, model, value) {
    $event.preventDefault();
    const currRole = model.filter(v => v.role === value.role).length;
    currRole ? this.model = model.filter(v => v.role !== value.role) : model.push(value);
    this.onUpdate($event);
  }

  toggleselectedCategory($event, model, value) {
    $event.preventDefault();
    const categoryItems = this.items.filter(role => role.type === value);
    this.selectedAllInCattegory(value) ? this.model = this.model.filter(role => role.type !== value) : categoryItems.forEach(role => {
      if (!model.filter(mod => mod.role === role.role).length) {this.model.push(role); }
    });
    this.onUpdate($event);
  }

  toggleSelectedCloud($event, model, category, cloud) {
    $event.preventDefault();
    const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
    this.selectedAllInCloud(category, cloud) ? this.model = this.model.filter(role => {
      if (role.type === category && role.cloud === cloud) {
        return false;
      }
      return true;
    }) : categoryItems.forEach(role => {
      if (!model.filter(mod => mod.role === role.role).length) {this.model.push(role); }
    });
    this.onUpdate($event);
  }

  selectAllOptions($event) {
    $event.preventDefault();
    this.model = [...this.items];
    this.onUpdate($event);
    $event.preventDefault();
  }

  deselectAllOptions($event) {
    this.model = [];
    this.onUpdate($event);
    $event.preventDefault();
  }

  onUpdate($event): void {
    this.selectionChange.emit({ model: this.model, type: this.type, $event });
  }

  public toggleItemsForLable(label, $event) {
    this.isOpenCategory[label] = !this.isOpenCategory[label];
    this.isCloudOpen[label + 'AWS'] = false;
    this.isCloudOpen[label + 'GCP'] = false;
    this.isCloudOpen[label + 'AZURE'] = false;
    $event.preventDefault();
  }

  public toggleItemsForCloud(label, $event) {
    this.isCloudOpen[label] = !this.isCloudOpen[label];
    $event.preventDefault();
  }

  public selectedAllInCattegory(category) {
    const selected = this.model.filter(role => role.type === category);
    const categoryItems = this.items.filter(role => role.type === category);
    return selected.length === categoryItems.length;
  }

  public selectedSomeInCattegory(category) {
    const selected = this.model.filter(role => role.type === category);
    const categoryItems = this.items.filter(role => role.type === category);
    return selected.length && selected.length !== categoryItems.length;
  }

  public selectedAllInCloud(category, cloud) {
    const selected = this.model.filter(role => role.type === category && role.cloud === cloud);
    const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
    return selected.length === categoryItems.length;
  }

  public selectedSomeInCloud(category, cloud) {
    const selected = this.model.filter(role => role.type === category && role.cloud === cloud);
    const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
    return selected.length && selected.length !== categoryItems.length;
  }

  public checkInModel(item) {
    return this.model.filter(v => v.role === item).length;
  }

  public selectedRolesList() {
    return this.model.map(role => role.role).join(',');
  }
}
