import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router, ActivationEnd } from '@angular/router';
import { ServiceService } from 'src/app/openApis/serviceInventoryManagement/services';
import { ToastrService } from 'ngx-toastr';
import { Service, ServiceUpdate } from 'src/app/openApis/serviceActivationAndConfiguration/models';
import { UntypedFormGroup, UntypedFormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { trigger } from '@angular/animations';
import { fadeIn } from 'src/app/shared/animations/animations';
import { MatDialog } from '@angular/material/dialog';
import { SortingService } from 'src/app/shared/functions/sorting.service';
import { AuthService } from 'src/app/shared/services/auth.service';
import { EditServiceCharacteristicsComponent } from '../edit-service-characteristics/edit-service-characteristics.component';
import { AppService } from 'src/app/shared/services/app.service';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { JsonEditorOptions } from 'ang-jsoneditor';
import { ExecuteManoServicePrimitiveComponent } from '../execute-mano-service-primitive/execute-mano-service-primitive.component';
import { HttpErrorResponse } from '@angular/common/http';


@Component({
  selector: 'app-preview-service',
  templateUrl: './preview-service.component.html',
  styleUrls: ['./preview-service.component.scss'],
  animations: [ trigger('fadeIn', fadeIn()) ]
})
export class PreviewServiceComponent implements OnInit {

  constructor(
    private activatedRoute: ActivatedRoute,
    private serviceService: ServiceService,
    private toast: ToastrService,
    private router: Router,
    private dialog: MatDialog,
    private sortingService: SortingService,
    private authService: AuthService,
    private toastr: ToastrService,
    public appService: AppService
  ) { }

  serviceID: string
  service: Service
  newService: boolean = false
  serviceNotFound: boolean = false
  finishedLoading: boolean = false

  editForm = new UntypedFormGroup({
    state: new UntypedFormControl(),
    note: new UntypedFormControl(),
    startDate: new UntypedFormControl(),
    endDate: new UntypedFormControl()
  })
  editMode: boolean = false
  isAdminUser: boolean = false

  newNote: boolean = false
  availableStates = ['feasibilityChecked', 'designed', 'reserved', 'inactive', 'active', 'terminated']

  subscriptions = new Subscription()

  listItems = ["Main Properties", "Service Characteristics", "Supporting Services", "Supporting Resources", "Contextual Features"]
  activeListItem = "Main Properties"

  jsonEditorOptions = new JsonEditorOptions()

  ngOnInit() {
    this.isAdminUser = this.authService.portalUserJWT.realm_access.roles.includes('ADMIN')

    this.initSubscriptions()

    if (this.activatedRoute.snapshot.params.id)
    {
      this.serviceID = this.activatedRoute.snapshot.params.id
      this.retrieveService()
      this.configureJSONEditor()
    } else {
      this.newService = true
    }

  }

  initSubscriptions() {
    this.subscriptions.add(this.router.events.subscribe(
      event => {
        if (event instanceof ActivationEnd && event.snapshot.params && event.snapshot.params.id) {
          this.serviceID = this.activatedRoute.snapshot.params.id
          this.retrieveService()
        }
      }
    ))
  }

  configureJSONEditor() {
    this.jsonEditorOptions.mode = "view"
    this.jsonEditorOptions.sortObjectKeys = true
    this.jsonEditorOptions.name = "NSLCM"
  }


  retrieveService() {
    this.serviceService.retrieveService({id: this.serviceID}).subscribe(
      data => {
        this.service = data
      },
      error => {
        console.error(error)
      },
      () => {
        this.finishedLoading = true
        if (!this.service) {
          this.serviceNotFound = true
        }
        this.service.serviceCharacteristic.sort(this.sortingService.ascStringSortingFunctionByNameProperty())
        this.service.note.sort(this.sortingService.ascDateSortingFuncByDateProperty())
        this.editForm.patchValue({
          state: this.service.state,
          startDate: this.service.startDate,
          endDate: this.service.endDate
        })

        // only populate contextual features tab if the service = RFS. "ResourceFacingServiceSpecification" check remains for backwards compatibility, as it has been correctly changed to "ResourceFacingService"
        if (this.service.category === "ResourceFacingService" || "ResourceFacingServiceSpecification") {
          this.populateContextualFeatures()
        }
      }
    )
  }

  // Main properties Tab block
  //

  triggerNewNote() {
    if (this.newNote) this.editForm.get('note').reset()
    this.newNote = !this.newNote
  }

  selectListitem(item: string) {
    this.activeListItem = item
  }

  enableServiceEditing() {
    this.editMode = true
  }

  cancelServiceEditing() {
    this.editForm.patchValue({
      state: this.service.state,
      startDate: this.service.startDate,
      endDate: this.service.endDate
    })
    this.editMode = false
  }

  submitServiceEditing() {
    this.editMode = false
    let serviceUpdate: ServiceUpdate = {
      state: this.editForm.get('state').value,
      startDate: this.editForm.get('startDate').value,
      endDate: this.editForm.get('endDate').value
    }
    if (this.editForm.get('note').value) {
      serviceUpdate.note = [{
        author:this.authService.portalUserJWT.preferred_username,
        text: this.editForm.get('note').value,
        date: new Date().toISOString()
      }]
    }

    this.serviceService.patchService({service: serviceUpdate, id: this.serviceID}).subscribe(
      data => { this.toast.success("Service is successfully updated") },
      error => { console.error(error), this.toastr.error("An error occurred updating this Service") },
      () => {
        this.triggerNewNote()
        this.retrieveService()
      }
    )
  }

  serviceStateClassSelector(state:'feasibilityChecked'| 'designed'| 'reserved'| 'inactive'| 'active'| 'terminated') {
    let cssClass: string = 'badge'
    switch (state) {
      case 'feasibilityChecked':
        cssClass += ' badge-primary'
        break;
      case 'inactive':
        cssClass += ' badge-secondary'
        break;
      case 'terminated':
        cssClass += ' badge-danger'
        break;
      case 'active':
        cssClass += ' badge-success'
        break;
      default:
        cssClass += ' badge-warning'
    }
    return cssClass
  }

  //
  // ENDOF Main properties Tab block


  // Service Characteristics Tab block
  //
  openCharacteristicsEditDialog() {
    const dialogRef = this.dialog.open(EditServiceCharacteristicsComponent, {
      data: {
        service: this.service,
      },
      minWidth: "60vw"
    })

    dialogRef.afterClosed().subscribe(
      result => {
        if (result) {
          this.toast.success("Service is successfully updated")
        }
        this.retrieveService()
      }
    )
  }

  //
  // ENDOF Service Characteristics Tab block

  
  // Contextual Features Tab block
  //
  NSLCMCharacteristic
  NSLCMObject
  primitivesListCharacteristic
  
  vnfPrimListDisplayColumns = ["VNF Profile ID", "Primitive", "Primitive Parameters", "Actions"]
  vnfPrimListDatasource = new MatTableDataSource()
  @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;

  populateContextualFeatures() {
    this.NSLCMCharacteristic = this.service.serviceCharacteristic.find(el => el.name === "NSLCM")
    this.primitivesListCharacteristic = this.service.serviceCharacteristic.find(el => el.name === "PrimitivesList")
    
    // NSLCM display feature
    const NSLCMCharacteristicValue = this.NSLCMCharacteristic?.value?.value
    if (NSLCMCharacteristicValue) {
      try {
        this.NSLCMObject = JSON.parse(NSLCMCharacteristicValue)
      }
      catch {
        this.NSLCMObject = {}
      }
    }
    
    // Primitives List feature
    const primitivesListObjectValue = this.primitivesListCharacteristic?.value?.value
    
    let primitivesListObject
    if (primitivesListObjectValue) {
      try {
        primitivesListObject = JSON.parse(primitivesListObjectValue)
      }
      catch {
        primitivesListObject = {}
      }
    }
    
    if (this.primitivesListCharacteristic && primitivesListObject) {
      
      // list VNF-level primitives
      const vnfPrimitives = primitivesListObject['vnfs']
      if (vnfPrimitives && vnfPrimitives.length) { 
        let primListDataSource: { "vnf_id":string, "primitive":{"name":string, "parameter"?:{"name":string, "data-type":string}[]} }[] = []
        vnfPrimitives.forEach( vnf => {
          if (vnf['config-primitive'] && vnf['config-primitive'].length) {
            vnf['config-primitive'].forEach ( primitive => {
              // if the vnf primitive has parameters
              if (primitive?.parameter && primitive?.parameter?.length) {
                primListDataSource.push({"vnf_id":vnf.id, "primitive": {"name":primitive.name, "parameter": primitive.parameter}})
              } 
              // if the vnf primitive does not have parameters
              else {
                primListDataSource.push({"vnf_id":vnf.id, "primitive": {"name":primitive.name}})
              }
            })
          }
        })
        this.vnfPrimListDatasource.data = primListDataSource
        this.vnfPrimListDatasource.paginator = this.paginator
      }
    }
  }

  openExecutePrimitiveDialog(element: {"vnf_id":string, "primitive":{"name":string, "parameter"?:{"name":string, "data-type":string}[]}}) {
    const dialogRef = this.dialog.open(ExecuteManoServicePrimitiveComponent, {
      data: {
        primitiveType: "VNF-level Primitive",
        serviceToBeUpdated: this.service,
        primitive: element
      }
    })

    dialogRef.afterClosed().subscribe (
      result => {
        if (result instanceof HttpErrorResponse) {
          this.toast.error("An error occurred while attempting to queue the service primitive for execution")
        } else {
          // check if something is returned from the dialog (updated service object) or the dialog is cancelled
          if (result) {
            this.toast.success("The service primitive was successfully queued for execution. Please check NSLCM for updates.")
            this.retrieveService()
          }
        }
      }
    )
  }

  applyVNFPrimListFilter(filterValue: string) {
    filterValue = filterValue.trim();
    filterValue = filterValue.toLowerCase();
    this.vnfPrimListDatasource.filter = filterValue;
  }
  //
  // Contextual Features Tab block

  ngOnDestroy() {
    this.subscriptions.unsubscribe()
  }
}
