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 { Observable, of } from 'rxjs';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { INetworkModel } from '@fleio-api/openstack/model/network.model';
import { NetworksApiService } from '@fleio-api/openstack/network/networks-api.service';
import { NotificationService } from '@shared/ui-api/notification.service';
import { INetworkCreateOptionsModel } from '@fleio-api/openstack/network/model/network-create-options.model';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';
import { MatChipEditedEvent, MatChipInputEvent } from '@angular/material/chips';
import { COMMA } from '@angular/cdk/keycodes';
import { ENTER } from '@angular/cdk/keycodes';

@Component({
  selector: 'app-network-edit-form',
  templateUrl: './network-edit-form.component.html',
  styleUrls: ['./network-edit-form.component.scss']
})
export class NetworkEditFormComponent extends DetailsFormBase<INetworkModel> implements OnInit {
  networkForm = this.formBuilder.group({
    client: ['', Validators.required],
    name: ['', Validators.required],
    description: [''],
    region: ['', Validators.required],
    provider_network_type: ['', Validators.required],
    admin_state_up: [true],
    router_external: [false],
    is_default: [false],
    shared: [false],
    mtu: [1500, [ValidatorsHelper.requiredIntegerValidator, Validators.min(1), Validators.max(1500)]],
    dns_domain: [''],
    port_security_enabled: [true],
    tags: [[]],
  });
  clientControl = this.networkForm.controls.client;
  createOptions: INetworkCreateOptionsModel;
  showProviderPhysical = false;
  showProviderSegmentationID = false;
  minSegmentationID = null;
  maxSegmentationID = null;
  createInClientProject = true;

  readonly separatorKeysCodes = [ENTER, COMMA] as const;

  constructor(
    private formBuilder: UntypedFormBuilder,
    private networksApiService: NetworksApiService,
    private router: Router,
    private config: ConfigService,
    private notificationService: NotificationService,
  ) {
    super();
  }

  changeDestination(value: any) {
    // createInClientProject
    if (value === false) {
      this.clientControl.setValue('');
      this.clientControl.clearValidators();
      this.clientControl.reset();
    } else {
      this.clientControl.setValidators(Validators.required);
    }
  }

  updateProviderFields(selectedProviderType: any) {
    this.showProviderPhysical = this.createOptions.provider_types[selectedProviderType].require_physical_network;
    this.showProviderSegmentationID = this.createOptions.provider_types[selectedProviderType].require_segmentation_id;
    if (this.showProviderPhysical) {
      this.networkForm.addControl('provider_physical_network', this.formBuilder.control(['']));
    } else {
      if (this.networkForm.contains('provider_physical_network')) {
        this.networkForm.removeControl('provider_physical_network');
      }
    }
    if (this.showProviderSegmentationID) {
      this.networkForm.addControl('provider_segmentation_id', this.formBuilder.control(null));
    } else {
      if (this.networkForm.contains('provider_segmentation_id')) {
        this.networkForm.removeControl('provider_segmentation_id');
      }
    }
    if (this.createOptions?.segmentation_id_range[selectedProviderType] &&
      this.networkForm.contains('provider_segmentation_id')) {
      this.minSegmentationID = this.createOptions.segmentation_id_range[selectedProviderType][0];
      this.maxSegmentationID = this.createOptions.segmentation_id_range[selectedProviderType][1];
      this.networkForm.controls.provider_segmentation_id.setValidators([
        Validators.min(this.minSegmentationID), Validators.max(this.maxSegmentationID)
      ]);
    } else {
      this.minSegmentationID = null;
      this.maxSegmentationID = null;
    }
  }

  ngOnInit() {
    super.ngOnInit();
    if (this.objectController) {
      this.objectController.actionCallback = () => this.networksActions();
      this.createOptions = this.objectController.additionalObjects.createOptions as INetworkCreateOptionsModel;
    }

    if (this.createOptions && this.createOptions.availability_zones &&
      this.authSvc.feature('openstack.networks.availability_zones') &&
      this.createOptions.availability_zones.length && !this.object?.id) {
      this.networkForm.addControl('availability_zone_hints', this.formBuilder.control([]));
    }

    if (!this.authSvc.feature('openstack.networks.auto_create_network')) {
      this.networkForm.removeControl('is_default');
    }

    this.networkForm.controls.router_external.valueChanges.subscribe(newValue => {
      if (newValue) {
        this.networkForm.controls.is_default.enable();
      } else {
        this.networkForm.controls.is_default.disable();
      }
    });

    if (this.object && this.object.id) {
      this.networkForm.patchValue(this.object);
      this.networkForm.controls.client.disable();
      this.networkForm.controls.region.disable();
      this.networkForm.controls.provider_network_type.disable();
    } else {
      if (this.createOptions) {
        let initialProviderType = 'local';
        if (this.createOptions.provider_types &&
          !this.createOptions.provider_types.hasOwnProperty(initialProviderType)) {
          for (const providerType in this.createOptions.provider_types) {
            if (this.createOptions.provider_types.hasOwnProperty(providerType)) {
              initialProviderType = providerType;
              break;
            }
          }
        }
        this.networkForm.controls.provider_network_type.setValue(initialProviderType);
        this.networkForm.controls.region.setValue(this.createOptions.selected_region);
        this.updateProviderFields(this.networkForm.controls.provider_network_type.value);
      }
      this.networkForm.controls.provider_network_type.valueChanges.subscribe(value => {
        this.updateProviderFields(value);
      });
    }
  }

  tagRemoved(tagToRemove: string) {
    let tags = this.networkForm.controls.tags.value as Array<string>;
    tags = tags.filter(tag => tag !== tagToRemove);
    this.networkForm.controls.tags.setValue(tags);
  }

  tagEdited(tag: string, event: MatChipEditedEvent) {
    const value = event.value.trim();

    // Remove tag if it no longer has a value
    if (!value) {
      this.tagRemoved(tag);
      return;
    }

    // Edit existing tag
    let tags = this.networkForm.controls.tags.value as Array<string>;
    const index = tags.indexOf(tag);
    if (index >= 0) {
      tags[index] = value;
      this.networkForm.controls.tags.setValue(tags);
    }
  }

  addTag(event: MatChipInputEvent) {
    const value = (event.value || '').trim();
    if (value) {
      const tags = this.networkForm.controls.tags.value as Array<string>;
      if (tags) {
        tags.push(value);
        this.networkForm.controls.tags.setValue(tags);
      } else {
        this.networkForm.controls.tags.setValue([value]);
      }
    }

    // Clear the input value
    event.chipInput!.clear();
  }

  networksActions(): Observable<IActionResult> {
    const value = this.networkForm.value;

    if (value.client && value.client.id) {
      value.client = value.client.id;
    }

    if (!this.object.id && !this.createInClientProject) {
      value.create_as_admin = true;
    }

    this.createOrUpdate(
      this.networksApiService,
      value,
    ).subscribe({
      next: () => {
        if (this.object.id) {
          this.notificationService.showMessage($localize`Network saved`);
        } else {
          this.notificationService.showMessage($localize`Network created`);
        }
        let url = this.config.getPanelUrl('openstack/networks');
        if (this.object.id) {
          url += `/${this.object.id}`;
        }
        if (this.object.id) {
          this.router.navigateByUrl(
            url
          ).catch(() => {
          });
        } else {
          this.router.navigate([url], {
            queryParamsHandling: 'merge'
          });
        }
      }, error: () => {
        this.notificationService.showMessage($localize`Failed to save network`);
      }
    });

    return of(null);
  }
}
