import {
  Component,
  EventEmitter,
  HostBinding,
  Input, OnChanges,
  OnInit,
  Output,
  ViewChild,
} from '@angular/core';
import { IImageModel } from '@fleio-api/openstack/model/image.model';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { IVolumeModel } from '@fleio-api/openstack/model/volume.model';
import { IVolumeType } from '@fleio-api/openstack/model/volume-type.model';
import { ConfigService } from '@shared/config/config.service';
import { IFlavorModel } from '@fleio-api/openstack/model/flavor.model';
import { NotificationService } from '@shared/ui-api/notification.service';
import { MatTabGroup } from '@angular/material/tabs';
import { ActivatedRoute } from '@angular/router';
import { AuthService } from '@shared/auth/auth.service';
import { IVolumeSnapshotModel } from '@fleio-api/openstack/model/volume-snapshot.model';
import { LanguageService } from '@shared/language/language.service';

export interface ISelectedBootSource {
  object: (IImageModel & IVolumeModel) | null;
  objectId: string | null;
  type?: string;
  createNewVolume: boolean;
  deleteOnTermination: boolean;
  volumeSize?: number;
  storageType?: string;
  cinderAZ: string;
  tabIndex?: number;
}

@Component({
  selector: 'app-boot-source-select',
  templateUrl: './boot-source-select.component.html',
  styleUrls: ['./boot-source-select.component.scss'],
  animations: [
    trigger('openCloseDialog', [
      state('closed', style({
        opacity: '0',
        left: '{{closedLeftOffset}}',
        right: '{{closedRightOffset}}'
      }), {
        params: {
          closedLeftOffset: '100%',
          closedRightOffset: '0'
        }
      }),
      state('open', style({
        opacity: '1',
        left: '{{leftOffset}}px',
        right: '{{rightOffset}}px'
      }), {
        params: {
          leftOffset: 330,
          rightOffset: 0
        }
      }),
      transition('open => closed', [
        animate('0.2s ease-out')
      ]),
      transition('closed => open', [
        animate('0.2s ease-out')
      ]),
    ]),
  ],
})
export class BootSourceSelectComponent implements OnInit, OnChanges {
  @ViewChild('bootSourcesTabGroup', {static: false}) bootSourcesTabGroup: MatTabGroup;
  @Input() images: IImageModel[];
  @Input() communityImages: IImageModel[];
  @Input() ownedImages: IImageModel[];
  @Input() sharedImages: IImageModel[];
  @Input() volumes: IVolumeModel[];
  @Input() volumeSnapshots: Array<IVolumeSnapshotModel>;
  @Input() requestedImages: Array<IImageModel>;
  @Input() volumeTypes: IVolumeType[];
  @Input() requestedBootSource: boolean;
  @Input() showStorageSelection = true;
  @Input() selectedFlavor: (IFlavorModel | null);
  @Input() selectedRegionName: string;
  @Input() cinderAz: Array<string>;
  @Input() hideVolumeAz: boolean;
  @Output() selectedBootSourceInter = new EventEmitter<ISelectedBootSource>();
  sizeIncrement: number | null;
  minimumSize: number | null;
  selectedBootSource: ISelectedBootSource | null;
  savedBootSource: ISelectedBootSource | null;
  showSources = false;
  selectedTab = 0;
  leftOffset: number;
  rightOffset: number;
  closedLeftOffset: string;
  closedRightOffset: string;
  trigger: any;
  isImageType = ['image', 'owned_image', 'community_image', 'shared_image', 'requested_image'];
  showCommunityImages: boolean;
  showSharedImages: boolean;

  constructor(
    public config: ConfigService,
    private notificationService: NotificationService,
    private activatedRoute: ActivatedRoute,
    public authService: AuthService,
    public languageService: LanguageService,
  ) {
  }

  @HostBinding('@openCloseDialog') get openCloseDialog() {
    const screenWidth = window.innerWidth;
    if (this.languageService.langDirection === 'ltr') {
      if (screenWidth > 1280) {
        this.leftOffset = 330;
        this.rightOffset = 0;
      } else {
        this.leftOffset = 0;
        this.rightOffset = 0;
      }
      this.closedLeftOffset = '100%';
      this.closedRightOffset = '0';
    } else {
      if (screenWidth > 1280) {
        this.rightOffset = 330;
        this.leftOffset = 0;
      } else {
        this.leftOffset = 0;
        this.rightOffset = 0;
      }
      this.closedLeftOffset = '0';
      this.closedRightOffset = '100%';
    }
    return {
      value: this.trigger,
      params: {
        leftOffset: this.leftOffset,
        rightOffset: this.rightOffset
      }
    };
  }

  public changedSource(type) {
    this.selectedBootSource.type = type;
    if (this.isImageType.indexOf(type) > -1) {
      this.setBootVolumeSize();
    }
  }

  public bootSourceIcon() {
    if (this.selectedBootSource && this.selectedBootSource.type) {
      if (this.isImageType.indexOf(this.selectedBootSource.type) > -1) {
        if (this.selectedBootSource.object) {
          return (this.selectedBootSource.object.os_distro || 'otheros').split('-').pop();
        } else {
          return 'otheros';
        }
      }
      if (this.selectedBootSource.type === 'volume' || this.selectedBootSource.type === 'volume_snapshot') {
        return 'volumes';
      }
    }
    return 'otheros';
  }

  getImageTooltip(image: IImageModel) {
    if (!image.assigned_to_flavor) {
      return $localize`Image is not assigned to the selected\nflavor or flavor group.`;
    }
    if (image.disabled) {
      return $localize`Image requires a flavor\nwith more resources.`;
    }
    return '';
  }

  public storageTypeChanged() {
    if (this.selectedBootSource.storageType === 'local') {
      this.selectedBootSource.createNewVolume = false;
      return;
    } else {
      this.selectedBootSource.createNewVolume = true;
      if (!this.sizeIncrement) {
        this.sizeIncrement = 1;
      }
      if (!this.minimumSize) {
        this.minimumSize = 1;
      }
    }
    let newSizeIncrement = 1;
    let newMinimumSize = 1;
    if (this.selectedBootSource.storageType) {
      this.volumeTypes.forEach((el) => {
        if (el.name === this.selectedBootSource.storageType) {
          newSizeIncrement = el.sizeIncrement;
          newMinimumSize = el.minimumSize;
        }
      });
    }
    this.sizeIncrement = newSizeIncrement;
    this.minimumSize = newMinimumSize;
    this.setBootVolumeSize();
  }

  private setBootVolumeSize() {
    const currentVolumeSize = (this.selectedBootSource.volumeSize ?
      this.selectedBootSource.volumeSize : this.minimumSize);
    if (this.selectedBootSource.object && this.selectedBootSource.object.min_disk > currentVolumeSize) {
      this.selectedBootSource.volumeSize = this.selectedBootSource.object.min_disk;
    } else {
      this.selectedBootSource.volumeSize = currentVolumeSize;
    }
    if (this.selectedBootSource.volumeSize) {
      while (this.selectedBootSource.volumeSize % this.sizeIncrement !== 0) {
        this.selectedBootSource.volumeSize = this.selectedBootSource.volumeSize + 1;
      }

      if (this.selectedBootSource.volumeSize < this.minimumSize) {
        this.selectedBootSource.volumeSize = this.minimumSize;
      }
    }
  }

  public validVolumeSize() {
    if (!this.selectedBootSource || !this.selectedBootSource.object) {
      return true;
    }
    const isImageSelected = this.isImageType.indexOf(this.selectedBootSource.type) > -1;
    if (typeof this.selectedBootSource.volumeSize !== 'number') {
      return false;
    }
    if (this.selectedBootSource.volumeSize % this.sizeIncrement !== 0) {
      return false;
    }
    if (isImageSelected && this.selectedBootSource && this.selectedBootSource.type &&
      this.selectedBootSource.object.min_disk) {
      if (this.selectedBootSource.volumeSize < this.selectedBootSource.object.min_disk) {
        return false;
      }
    }
    return true;
  }

  public setBootSourceObject(object) {
    this.selectedBootSource.object = object;
  }

  public makeSelection() {
    this.showSources = !this.showSources;
    this.emitBootSourceEvent();
    this.selectedBootSource.tabIndex = this.selectedTab;
    this.savedBootSource = JSON.parse(JSON.stringify(this.selectedBootSource));
  }

  public cancelSelection() {
    this.showSources = !this.showSources;
    this.selectedBootSource = JSON.parse(JSON.stringify(this.savedBootSource));
    if (this.savedBootSource && this.savedBootSource.tabIndex) {
      this.selectedTab = this.savedBootSource.tabIndex;
    } else {
      this.selectedTab = 0;
    }
  }

  private initBootSource(imagesList: Array<Array<IImageModel>> = null) {
    const defaultStorageType = this.getDefaultStorageType();
    const createNewVolume = defaultStorageType !== 'local';
    const imageId = this.activatedRoute.snapshot.queryParams.image_id || null;
    let image = null;
    let tabIndex = 0;
    if (!imagesList) {
      imagesList = [this.images, this.ownedImages, this.communityImages];
      if (Array.isArray(this.requestedImages)) {
        imagesList.push(this.requestedImages);
      }
    }
    for (const [index, imageList] of imagesList.entries()) {
      if (imageList) {
        image = imageList.find(i => i.id === imageId);
        if (image) {
          tabIndex = index;
          break;
        }
      }
    }

    this.selectedBootSource = {
      // When init, type will always be image because of first tab. This allows displaying volume options if necessary.
      type: 'image',
      objectId: image ? image.id : imageId,
      object: image ? image : null,
      tabIndex,
      createNewVolume,
      cinderAZ: 'fleio-auto',
      deleteOnTermination: true,
      storageType: this.getDefaultStorageType(),
    };
    this.storageTypeChanged();
    this.setBootVolumeSize();
    this.savedBootSource = JSON.parse(JSON.stringify(this.selectedBootSource));
    return this.selectedBootSource;
  }

  public showSideDialog() {
    this.showSources = !this.showSources;
    // initialize selected tab based on the saved value
    if (this.savedBootSource && this.savedBootSource.tabIndex) {
      this.selectedTab = this.savedBootSource.tabIndex;
    } else {
      this.bootSourcesTabGroup.realignInkBar();
      // has to be realigned due to a bug that doesn't show it if hidden at first
    }
  }

  public changedTab(tabEvent) {
    if (tabEvent.index >= 0) {
      this.selectedTab = tabEvent.index;
      if ([$localize`Public images`, $localize`Client images`, $localize`Community images`,
        $localize`Requested image`, $localize`Shared images`].indexOf(tabEvent.tab.textLabel) > -1) {
        this.selectedBootSource.type = 'image'; // type will correctly be set when choosing a new object or when
        // clicking cancel because of object reset from the saved boot source
      } else if ([$localize`Volume snapshots`].indexOf(tabEvent.tab.textLabel) > -1) {
        this.selectedBootSource.type = 'volume_snapshot';
      } else {
        this.selectedBootSource.type = 'volume';
      }
    }
  }

  public doubleClickedSource() {
    this.makeSelection();
  }

  private getDefaultStorageType(): string {
    if (this.config && this.config.current && this.config.current.settings) {
      let computeStorageEnabled = true;
      if (this.selectedFlavor) {
        if (this.selectedFlavor.root_gb > 0) {
          if (this.config.current.settings.instanceForm.hideVolumeSelectionForFlavorsWithDisk) {
            computeStorageEnabled = true; // only local storage type
          }
        } else {
          computeStorageEnabled = false; // always disable local storage when flavor has disk === 0
        }
      }
      if (computeStorageEnabled) {
        return 'local';
      } else {
        if (this.volumeTypes && this.volumeTypes.length) {
          if (this.config.current.settings.instanceForm.defaultVolumeType && this.selectedRegionName) {
            if (this.config.current.settings.instanceForm.defaultVolumeType.hasOwnProperty(this.selectedRegionName)) {
              let foundVolumeType = false;
              for (const volumeType of this.volumeTypes) {
                if (volumeType.name === this.config.current.settings.instanceForm.defaultVolumeType[this.selectedRegionName]) {
                  foundVolumeType = true;
                  break;
                }
              }
              if (foundVolumeType) {
                return this.config.current.settings.instanceForm.defaultVolumeType[this.selectedRegionName];
              } else {
                return this.volumeTypes[0].name;
              }
            } else {
              return this.volumeTypes[0].name;
            }
          } else {
            return this.volumeTypes[0].name;
          }
        }
      }
    }
    return 'local';
  }

  // TODO: create method to de-select source when region changes or select a similar one
  ngOnInit() {
    this.leftOffset = 330;
    this.sizeIncrement = 1;
    const defaultStorageType = this.getDefaultStorageType();
    const createNewVolume = defaultStorageType !== 'local';
    this.savedBootSource = {
      tabIndex: 0,
      objectId: null,
      createNewVolume,
      deleteOnTermination: true,
      object: undefined,
      storageType: defaultStorageType,
      cinderAZ: 'fleio-auto',
    };
    this.initBootSource();
    this.showCommunityImages = !this.requestedBootSource && this.authService.feature('openstack.images.showcommunity');
    this.showSharedImages = !this.requestedBootSource && this.authService.feature('openstack.images.showshared');
  }

  showVolumeOptions() {
    return this.authService.feature('openstack.volumes') && this.selectedBootSource &&
      (this.isImageType.indexOf(this.selectedBootSource.type) > -1) &&
      !(this.config.current.settings.instanceForm.hideVolumeSelectionForFlavorsWithDisk &&
        this.selectedFlavor && this.selectedFlavor.root_gb > 0);
  }

  ngOnChanges(changes) {
    if (changes.selectedFlavor && changes.selectedFlavor.currentValue) {
      const newFlavor = changes.selectedFlavor.currentValue;
      if (this.selectedBootSource && this.selectedBootSource.createNewVolume) {
        if (newFlavor.root_gb > 0 && this.config.current.settings.instanceForm.hideVolumeSelectionForFlavorsWithDisk) {
          this.initBootSource();
          this.notificationService.showMessage(
            $localize`Please reselect boot source as selected flavor cannot be used with volumes.`
          );
        }
      } else {
        if (newFlavor.root_gb === 0 && this.selectedBootSource && this.selectedBootSource.object &&
          this.selectedBootSource.type !== 'volume' && this.selectedBootSource.type !== 'volume_snapshot') {
          this.initBootSource();
          this.notificationService.showMessage(
            $localize`Please reselect boot source as selected flavor cannot be used without volumes.`
          );
        }
      }
    }
  }

  public similarBootSourceWasSet() {
    this.selectedBootSource.tabIndex = 0;
    this.emitBootSourceEvent();
    this.savedBootSource = JSON.parse(JSON.stringify(this.selectedBootSource));
  }

  private emitBootSourceEvent() {
    const bootSource = {...this.selectedBootSource};
    if (['volume', 'volume_snapshot'].indexOf(bootSource.type) >= 0) {
      bootSource.deleteOnTermination = false;
    }
    this.selectedBootSourceInter.emit(bootSource);
  }
}
