import { Component, OnInit } from '@angular/core';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ConfigService } from '@shared/config/config.service';
import { NotificationService } from '@shared/ui-api/notification.service';
import { EMPTY, Observable, of } from 'rxjs';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { IHeatStackModel } from '@fleio-api/openstack/orchestration/model/heat-stack.model';
import { HeatStacksApiService } from '@fleio-api/openstack/orchestration/heat-stacks/heat-stacks-api.service';
import { IAction } from '@objects-view/interfaces/actions/action';
import {
  IParameterGroupModel,
  ITemplateValidationResultsModel
} from '@fleio-api/openstack/orchestration/model/template-validation-results.model';
import { IApiUserModel } from '@fleio-api/openstack/model/api-user.model';
import { MatDialog } from '@angular/material/dialog';
import { HeatStackPreviewDialogComponent } from '../../dialogs/heat-stack-preview-dialog/heat-stack-preview-dialog.component';
import { IHeatStackPreviewModel } from '@fleio-api/openstack/orchestration/model/heat-stack-preview.model';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';

@Component({
  selector: 'app-heat-stack-edit-form',
  templateUrl: './heat-stack-edit-form.component.html',
  styleUrls: ['./heat-stack-edit-form.component.scss']
})
export class HeatStackEditFormComponent extends DetailsFormBase<IHeatStackModel> implements OnInit {
  parametersGroup = this.formBuilder.group([]);
  heatStackForm = this.formBuilder.group({
    template_source: ['direct-input', Validators.required],
    template_file: [''],
    template_data: [''],
    template_url: [''],
    environment_source: ['file'],
    environment_file: [''],
    environment_data: [''],

    stack_name: ['', Validators.required],
    creation_timeout: [60, ValidatorsHelper.requiredNumericValueValidator],
    rollback_on_failure: [false],
    parameters: this.parametersGroup,
  });
  step = 'validate-template';
  private templateFile: File;
  private environmentFile: File;
  validationResults: ITemplateValidationResultsModel;
  parameterNames: string[];
  parameterGroups: IParameterGroupModel[];
  apiUsers: IApiUserModel[];
  private finalizePostAction: string;

  constructor(
    private formBuilder: UntypedFormBuilder, private heatStacksApiService: HeatStacksApiService,
    private router: Router, private config: ConfigService, private notificationService: NotificationService,
    private matDialog: MatDialog,
  ) {
    super();
  }

  ngOnInit() {
    super.ngOnInit();
    if (this.objectController) {
      this.objectController.actionCallback = (action) => this.stackAction(action);
    }

    this.heatStackForm.controls.stack_name.disable();
    this.heatStackForm.controls.creation_timeout.disable();
    this.heatStackForm.controls.rollback_on_failure.disable();
    this.heatStackForm.controls.parameters.disable();

    if (this.object?.id) {
      this.heatStackForm.controls.stack_name.setValue(this.object.stack_name);
    }
  }

  enableFinalizeControls() {
    if (this.objectController.state !== 'change-template') {
      this.heatStackForm.controls.stack_name.enable();
    }
    this.heatStackForm.controls.creation_timeout.enable();
    this.heatStackForm.controls.rollback_on_failure.enable();
    this.heatStackForm.controls.parameters.enable();
  }

  goToFinalizeStep(action: IAction) {
    switch (this.objectController.state) {
      case 'create':
        action.name = $localize`Launch`;
        this.finalizePostAction = null;
        break;
      case 'preview':
        action.name = $localize`Preview`;
        this.finalizePostAction = 'preview';
        break;
      case 'change-template':
        action.name = $localize`Update`;
        this.finalizePostAction = 'change-template';
        break;
    }
    this.enableFinalizeControls();

    if (this.validationResults.ParameterGroups) {
      this.parameterGroups = this.validationResults.ParameterGroups;
    } else {
      this.parameterGroups = [];
    }

    this.parameterNames = Object.keys(this.validationResults.Parameters);

    const ungroupedParameters: IParameterGroupModel = {
      label: null,
      parameters: [],
    };

    for (const parameterName of this.parameterNames) {
      if (!this.parameterGroups.find(pg => pg.parameters.includes(parameterName))) {
        ungroupedParameters.parameters.push(parameterName)
      }
    }

    if (ungroupedParameters.parameters.length) {
      this.parameterGroups.splice(0, 0, ungroupedParameters);
    }

    for (const paramName of this.parameterNames) {
      const param = this.validationResults.Parameters[paramName];
      this.parametersGroup.addControl(
        paramName,
        this.formBuilder.control(param.Default),
      );
    }

    this.step = 'finalize';
  }

  private stackAction(action: IAction): Observable<IActionResult> {
    this.validate();
    if (this.formGroup.invalid) {
      this.displayControlErrors();
      return EMPTY;
    }

    const value = this.heatStackForm.value as any;
    value.step = this.step;

    delete value.template_file;
    delete value.environment_file;
    delete value.parameters;

    const formData = new FormData();
    Object.keys(value).map(fieldName => {
      formData.append(fieldName, value[fieldName]);
    });

    formData.append('parameters', JSON.stringify(this.parametersGroup.value));

    if (this.templateFile) {
      formData.append('template_file', this.templateFile, this.templateFile.name);
    }
    if (this.environmentFile) {
      formData.append('environment_file', this.environmentFile, this.environmentFile.name);
    }

    this.objectController.loading = true;
    if (this.step === 'validate-template') {
      action.disabled = true;
      this.heatStacksApiService.validateTemplate(formData).subscribe((validationResults) => {
        this.validationResults = validationResults;
        this.goToFinalizeStep(action);
      }, (error) => {
        if (error.error) {
          this.setErrors(error.error);
        }
      }).add(() => {
        action.disabled = false;
        this.objectController.loading = false;
      });
      return of(null);
    } else {
      let request;
      if (this.objectController.state === 'change-template') {
        request = this.heatStacksApiService.objectPostActionWithUpload(
          this.object.id, formData, this.finalizePostAction
        );
      } else {
        request = this.heatStacksApiService.postActionWithUpload(
          formData, this.finalizePostAction
        );
      }

      request.subscribe((stackData: IHeatStackPreviewModel) => {
        if (this.objectController.state === 'preview') {
          this.matDialog.open(
            HeatStackPreviewDialogComponent, {
              data: stackData,
              autoFocus: false,
            }).afterClosed().subscribe(() => {
            this.router.navigateByUrl(this.config.getPanelUrl('openstack/heat-stacks')).then(() => {
            });
          });
        } else {
          if (this.objectController.state === 'create') {
            this.notificationService.showMessage($localize`Heat stack creation scheduled`);
          } else {
            this.notificationService.showMessage($localize`Heat stack update scheduled`);
          }
          this.router.navigateByUrl(this.config.getPanelUrl('openstack/heat-stacks')).then(() => {
          });
        }
      }, (error) => {
        this.objectController.loading = false;
        if (error.error) {
          this.setErrors(error.error);
        }
      });
      return of(null);
    }
  }

  templateFileChanged($event: Event) {
    const files = ($event.target as HTMLInputElement).files;
    this.templateFile = files.length > 0 ? files[0] : null;
    this.heatStackForm.controls.template_file.setValue(this.templateFile.name);
  }

  environmentFileChanged($event: Event) {
    const files = ($event.target as HTMLInputElement).files;
    this.environmentFile = files.length > 0 ? files[0] : null;
    this.heatStackForm.controls.environment_file.setValue(this.environmentFile.name);
  }
}
