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

@Component({
  selector: 'app-edit-scada-password',
  standalone: false,
  templateUrl: './edit-scada-password.component.html',
  styleUrl: './edit-scada-password.component.css'
})
export class EditScadaPasswordComponent implements OnInit {
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  showLastPassword: boolean;
  showNewPassword: boolean;
  generalMatcher: GeneralMatcher | null;
  samePasswords: boolean;
  
  passMinLength: number;
  passMinUpper: number;
  passMinNumber: number;
  passMinChars: number;

  scadaPasswordFormGroup: FormGroup;

  constructor(
    private _dialogRef: MatDialogRef<EditScadaPasswordComponent>,
    private _systemAdminService: SystemAdminService,
    private _resourcesService: ResourcesService,
    private _encService: EncService,
  ){
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = "";
    this.showLastPassword = false;
    this.showNewPassword = false;
    this.generalMatcher = new GeneralMatcher();
    this.samePasswords = false;
    
    this.passMinLength = 0;
    this.passMinUpper = 0;
    this.passMinNumber = 0;
    this.passMinChars = 0;

    this.scadaPasswordFormGroup = new FormGroup({
      lastPaswordControl: new FormControl('', Validators.required),
      newPasswordControl: new FormControl(''),
    });
  }

  ngOnInit(): void {
    this.getPasswordRules();

    this.scadaPasswordFormGroup.controls['lastPaswordControl'].valueChanges.subscribe(lastPassword => {
      let newPassword = this.scadaPasswordFormGroup.controls['newPasswordControl'].value;
      if(lastPassword == newPassword){
        this.samePasswords = true;
        this._resourcesService.openSnackBar('Las contraseñas ingresadas son iguales.');
      }else{
        this.samePasswords = false;
      }
    });

    this.scadaPasswordFormGroup.controls['newPasswordControl'].valueChanges.subscribe(newPassword => {
      let lastPassword = this.scadaPasswordFormGroup.controls['lastPaswordControl'].value;
      if(lastPassword == newPassword){
        this.samePasswords = true;
        this._resourcesService.openSnackBar('Las contraseñas ingresadas son iguales.');
      }else{
        this.samePasswords = false;
      }
    })
  }
  
  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.scadaPasswordFormGroup.controls['newPasswordControl'].setValidators([
          Validators.minLength(passwordPattern.response.password_format.min_length),
          Validators.required,
        ]);
        
        this.passMinLength = passwordPattern.response.password_format.min_length;
        this.scadaPasswordFormGroup.addValidators(this.whiteSpacesValidator);

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

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

        if(passwordPattern.response.password_format.chars_enabled){
          this.passMinChars = passwordPattern.response.password_format.min_chars;
          this.scadaPasswordFormGroup.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('newPasswordControl')!.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('newPasswordControl')!.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('newPasswordControl')!.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('newPasswordControl')!.value;
    return !pass.includes(' ') ? null : { whiteSpaces: true }
  }

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

  avoidPaste(): boolean{
    this._resourcesService.openSnackBar('No se puede pegar información en este campo');
    return false;
  }

  async savePassword() {
    let passwordsStr = JSON.stringify(this.scadaPasswordFormGroup.getRawValue());
    let passwordsEnc = await this._encService.encrypt(passwordsStr);

    this._dialogRef.close(passwordsEnc);
  }
}
