import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import { SystemAdminService } from '../../../../../services/system-admin.service';
import { lastValueFrom } from 'rxjs';
import { PasswordFormatResponse } from '../../../../../interfaces/password-format.interface';
import { GeneralMatcher, VALID_CHARS } from '../../../../users-profiles/users-admin/new-user/new-user.component';
import { EncService } from '../../../../../services/enc.service';
import { SCADADetailsResponse } from '../../../../../interfaces/scada-list.interface';

@Component({
    selector: 'app-register-scada',
    templateUrl: './register-scada.component.html',
    styleUrl: './register-scada.component.css',
    standalone: false
})
export class RegisterScadaComponent implements OnInit {
  isNew: boolean;
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  scadaName: string;
  scadaPass: string;
  showPassword: boolean;
  scadaConfigFormGroup: FormGroup;
  generalMatcher: GeneralMatcher | null;
  
  passMinLength: number;
  passMinUpper: number;
  passMinNumber: number;
  passMinChars: number;

  constructor(
    @Inject(MAT_DIALOG_DATA) private _data: any,
    private _dialogRef: MatDialogRef<RegisterScadaComponent>,
    private _systemAdminService: SystemAdminService,
    private _encService: EncService,
  ) { 
    this.isNew = true;
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = "";
    this.scadaName = "";
    this.scadaPass = "";
    this.showPassword = false;
    this.generalMatcher = new GeneralMatcher();
    
    this.passMinLength = 0;
    this.passMinUpper = 0;
    this.passMinNumber = 0;
    this.passMinChars = 0;

    this.scadaConfigFormGroup = new FormGroup({
      scadaNameControl: new FormControl('', Validators.required),
      scadaPassControl: new FormControl(''),
    });
  }

  ngOnInit(): void {
    if(this._data.type == 'new'){
      this.getPasswordRules();
    }else{
      this.isNew = false;
      this.getSCADA();
    }
  }

  async getSCADA(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let scadaDetails: SCADADetailsResponse = await lastValueFrom(this._systemAdminService.getSCADA(this._data.id, idUser, 1));

      this.hasError = scadaDetails.error;
      this.errorStr = scadaDetails.msg;

      if(!this.hasError){
        this.scadaConfigFormGroup.controls['scadaNameControl'].setValue(scadaDetails.response.NOMBRESCADA);

        let passwordEncrypted = await this._encService.isEncrypted(scadaDetails.response.CONTRASCADA);
        if(passwordEncrypted){
          let passwordDec = await this._encService.decrypt(scadaDetails.response.CONTRASCADA);
          this.scadaConfigFormGroup.controls['scadaPassControl'].setValue(passwordDec);
        }else{
          this.scadaConfigFormGroup.controls['scadaPassControl'].clearValidators();
        }
      }

      this.isLoading = false;
    }catch(error: any){
      if(error.error == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else{
        this.errorStr = error.error.msg;
      }

      this.hasError = true;
      this.isLoading = false;
    }
  }

  async validateName(){
    let scadaConfigStr = JSON.stringify(this.scadaConfigFormGroup.getRawValue());
    let scadaConfigEnc = await this._encService.encrypt(scadaConfigStr);

    this._dialogRef.close(scadaConfigEnc);
  }

  private async getPasswordRules(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let passwordPattern: PasswordFormatResponse = await lastValueFrom(this._systemAdminService.getPasswordFormat(idUser, 1));

      this.hasError = passwordPattern.error;
      this.errorStr = passwordPattern.msg;

      if(!this.hasError && this.isNew){
        this.scadaConfigFormGroup.controls['scadaPassControl'].setValidators([
          Validators.minLength(passwordPattern.response.password_format.min_length),
          Validators.required,
        ]);
        
        this.passMinLength = passwordPattern.response.password_format.min_length;
        this.scadaConfigFormGroup.addValidators(this.whiteSpacesValidator);

        if(passwordPattern.response.password_format.upper_enabled){
          this.passMinUpper = passwordPattern.response.password_format.min_upper;
          this.scadaConfigFormGroup.addValidators(this.passMinUpperValidator);
        }

        if(passwordPattern.response.password_format.number_enabled){
          this.passMinNumber = passwordPattern.response.password_format.min_number;
          this.scadaConfigFormGroup.addValidators(this.passMinNumberValidator);
        }

        if(passwordPattern.response.password_format.chars_enabled){
          this.passMinChars = passwordPattern.response.password_format.min_chars;
          this.scadaConfigFormGroup.addValidators(this.passMinCharsValidator);
        }
      }

      this.isLoading = false;
    }catch(error: any){
      if(error.error == undefined){
        this.errorStr = "Ocurrió un error inesperado.";
      }else if(error.error.msg == undefined){
        this.errorStr = "Ocurrió un error inesperado.";
      }else{
        this.errorStr = error.error.msg;
      }

      this.hasError = true;
      this.isLoading = false;
    }
  }

  passMinUpperValidator: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('scadaPassControl')!.value;
    let valArr = pass.split('');
    let upperCount = 0;

    valArr.forEach((char: string) => {
      let upperRegex = new RegExp('[A-Z]');
      if(char.match(upperRegex)){
        upperCount++;
      }
    });
    
    return upperCount >= this.passMinUpper ? null : { minUpper: true }
  }

  passMinNumberValidator: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('scadaPassControl')!.value;
    let valArr = pass.split('');
    let numberCount = 0;

    valArr.forEach((char: string) => {
      let upperRegex = new RegExp('[0-9]');
      if(char.match(upperRegex)){
        numberCount++;
      }
    });

    return numberCount >= this.passMinNumber ? null : { minNumber: true }
  }
  
  passMinCharsValidator: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('scadaPassControl')!.value;
    let valArr = pass.split('');
    let charsCount = 0;

    valArr.forEach((char: string) => {
      let specialChars = VALID_CHARS;
      if(specialChars.includes(char)){
        charsCount++;
      }
    });
    
    return charsCount >= this.passMinChars ? null : { minChars: true }
  }

  whiteSpacesValidator: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('scadaPassControl')!.value;
    return !pass.includes(' ') ? null : { whiteSpaces: true }
  }

  getErrorMessage(control: string) {
    switch(control){
      case 'scadaNameControl':
        if(this.scadaConfigFormGroup.get('scadaNameControl')?.hasError('required')) return "Este campo es obligatorio.";
      break;
      case 'scadaPassControl':
        if(this.scadaConfigFormGroup.get('scadaPassControl')?.hasError('required')) return "Este campo es obligatorio.";
        if(this.scadaConfigFormGroup.get('scadaPassControl')?.hasError('minlength')) return `La contraseña debe tener al menos ${this.passMinLength} caracteres.`;
        if(this.scadaConfigFormGroup.errors != null && this.scadaConfigFormGroup.errors!['minUpper']) return `La contraseña debe contener al menos ${this.passMinUpper} letra(s) mayúscula(s).`;
        if(this.scadaConfigFormGroup.errors != null && this.scadaConfigFormGroup.errors!['minNumber']) return `La contraseña debe contener al menos ${this.passMinNumber} número(s).`;
        if(this.scadaConfigFormGroup.errors != null && this.scadaConfigFormGroup.errors!['minChars']) return `La contraseña debe contener al menos ${this.passMinChars} caracter(es) especial(es).`;
        if(this.scadaConfigFormGroup.errors != null && this.scadaConfigFormGroup.errors!['whiteSpaces']) return `La contraseña no debe contener espacios en blanco.`;
      break;
    }
    
    return "A";
  }
}
