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

@Component({
    selector: 'app-new-password',
    templateUrl: './new-password.component.html',
    styleUrl: './new-password.component.css',
    standalone: false
})
export class NewPasswordComponent implements OnInit {
  newPassword: FormGroup;
  hidePassword: boolean;
  hideConfirmPassword: boolean;

  isLoading: boolean;
  hasError: boolean;
  errorStr: string;

  samePassMatcher: NotSamePasswordsMatcher | null;
  generalMatcher: GeneralMatcher | null;
  passMinLength: number;
  passMinUpper: number;
  passMinNumber: number;
  passMinChars: number;

  constructor(
    @Inject(MAT_DIALOG_DATA) public data: any,
    private _systemAdminService: SystemAdminService,
  ) { 
    this.newPassword = new FormGroup({
      id: new FormControl(''),
      password: new FormControl('', [Validators.required, Validators.minLength(8)]),
      password_confirmation: new FormControl('', [Validators.required, Validators.minLength(8)])
    }, [this.checkPasswords, this.whiteSpacesValidator]);

    this.isLoading = true;
    this.hasError = false;
    this.errorStr = '';

    this.hidePassword = true;
    this.hideConfirmPassword = true;
    this.samePassMatcher = new NotSamePasswordsMatcher();
    this.generalMatcher = new GeneralMatcher();
    this.passMinLength = 0;
    this.passMinUpper = 0;
    this.passMinNumber = 0;
    this.passMinChars = 0;
  }

  ngOnInit(): void {
    this.newPassword.patchValue({
      id: this.data.id,
    });

    this.getPasswordPattern();
  }

  async getPasswordPattern(){
    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.newPassword.controls['password'].setValidators(Validators.minLength(passwordPattern.response.password_format.min_length));
        this.newPassword.controls['password_confirmation'].setValidators(Validators.minLength(passwordPattern.response.password_format.min_length));
        this.passMinLength = passwordPattern.response.password_format.min_length;

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

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

        if(passwordPattern.response.password_format.chars_enabled){
          this.passMinChars = passwordPattern.response.password_format.min_chars;
          this.newPassword.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;
    }
  }

  checkPasswords: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('password')?.value;
    let confPass = group.get('password_confirmation')?.value;
    return pass === confPass ? null : { notSame: true }
  }

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

  passMinUpperValidator: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
    let pass = group.get('password')!.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('password')!.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('password')!.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 }
  }

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