import { EncService } from './../../../../services/enc/enc.service';
import { lastValueFrom } from 'rxjs';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ProfilesResponse } from './../../../../interfaces/profiles.interface';
import { UserConsultResponse, UserConsult } from './../../../../interfaces/user.interface';
import { UsersProfilesService } from './../../../../services/users-profiles.service';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AbstractControl, FormControl, FormGroup, FormGroupDirective, NgForm, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import { Location } from '@angular/common';
import { ErrorStateMatcher } from '@angular/material/core';

@Component({
  selector: 'app-new-user',
  templateUrl: './new-user.component.html',
  styleUrls: ['./new-user.component.css']
})
export class NewUserComponent implements OnInit {
  action: string;
  user: string;
  isNew: boolean;
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  userConsult?: UserConsult;
  userForm: FormGroup;
  profiles: Array<any>;
  hide: boolean;
  saveEnabled: boolean;

  passMatcher = new NotSamePasswordsMatcher();

  constructor(
    private route: ActivatedRoute, 
    private usersProfilesService: UsersProfilesService, 
    private _location: Location, 
    private _snackBar: MatSnackBar,
    private _encService: EncService
  ) { 
    this.action = "";
    this.user = "";
    this.isNew = true;
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = "";
    this.profiles = [];
    this.hide = true;
    this.saveEnabled = true;

    this.userForm = new FormGroup({
      id: new FormControl(''),
      name: new FormControl('', [Validators.required, Validators.maxLength(50)]),
      fApe: new FormControl('', [Validators.required, Validators.maxLength(50)]),
      sApe: new FormControl('', Validators.maxLength(50)),
      email: new FormControl('', [Validators.required, Validators.maxLength(50), Validators.email]),
      perf: new FormControl('', Validators.required),
    });
  }

  ngOnInit(): void {
    this.route.queryParams.subscribe(params => {
      let info = params['info'];
      this._encService.desencriptar(info).then((infoDec) => {
        let infoObj = JSON.parse(infoDec);

        this.isNew = infoObj.action == "insert";
        this.action = infoObj.action == "insert" ? "Insertar Nuevo" : "Modificar";
        this.user = infoObj.user;
        
        if(this.isNew){
          this.userForm.addControl('password', new FormControl('', [Validators.required, Validators.minLength(8)]));
          this.userForm.addControl('password_confirmation', new FormControl('', [Validators.required, Validators.minLength(8)]));
          this.userForm.addValidators(this.checkPasswords);

          this.getProfiles();
        }else{
          this.getUser(this.user);
        }
      })
    });
  }

  async getUser(idUser: string){
    try{
      let idEnc = await this._encService.encriptar(idUser);
      let idShort = await lastValueFrom(this._encService.shortEncrypt(idEnc));
      
      let idEncSol = localStorage.getItem('idusuario');
      let idUserShort = await lastValueFrom(this._encService.shortEncrypt(idEncSol!));
      
      let userInfo: UserConsultResponse = await lastValueFrom(this.usersProfilesService.getUser(
        idShort.response.encrypted, 
        idUserShort.response.encrypted, 
        1
      ));
      console.log(userInfo);
      
      this.hasError = userInfo.error;

      if(!this.hasError){
        this.userConsult = userInfo.response;
        this.saveEnabled = this.userConsult.ESTATUS != 'Eliminado';

        await this.getProfiles();
        this.isLoading = false;

        this.userForm.patchValue({
          id: this.userConsult.IDUSUARIO,
          name: this.userConsult.NOMBRE,
          fApe: this.userConsult.APEPAT,
          sApe: this.userConsult.APEMAT,
          email: this.userConsult.EMAIL,
          perf: this.userConsult.PERFIL,
        });
      }else{
        this.isLoading = false;
        this.errorStr = userInfo.msg;
      }
    }catch(error: any){
      this.isLoading = false;
      this.hasError = true;
      
      if(error.error == undefined){
        this.errorStr = "Ocurrió un error inesperado.";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

  async getProfiles(){
    try{
      let idEnc = localStorage.getItem('idusuario');
      let idShort = await lastValueFrom(this._encService.shortEncrypt(idEnc!));
      
      let profiles: ProfilesResponse = await lastValueFrom(this.usersProfilesService.getProfiles(idShort.response.encrypted, 1));
      this.hasError = profiles.error;
      this.errorStr = profiles.msg;

      if(this.isNew){
        this.isLoading = false;
      }

      if(!this.hasError){
        profiles.response.forEach(item => {
          let profile = {
            IDPRO: item.IDPERFIL,
            NAPRO: item.NOMBREPERFIL
          };

          this.profiles.push(profile);
        });
      }else{
        this.isLoading = false;
      }
    }catch(error: any){
      this.isLoading = false;
      this.hasError = true;

      if(error.error == undefined){
        this.errorStr = "Ocurrió un error inesperado.";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

  async save(){
    let info = this.userForm.getRawValue();
    
    try{
      if(this.isNew){
        await lastValueFrom(this.usersProfilesService.newUser({
          id_user: localStorage.getItem('idusuario'),
          linea: 1,
          name: info.name,
          fApe: info.fApe,
          sApe: info.sApe == "" ? null : info.sApe,
          perf: info.perf,
          email: info.email,
          password: info.password,
          password_confirmation: info.password_confirmation,
        }));
        this.openSnackBar('El usuario fue registrado correctamente.');
      }else{
        let idEnc = await this._encService.encriptar(info.id);
        let idUser = localStorage.getItem('idusuario');

        await lastValueFrom(this.usersProfilesService.updateUser({
          id: idEnc,
          name: info.name,
          fApe: info.fApe,
          sApe: info.sApe == "" ? null : info.sApe,
          email: info.email,
          perf: info.perf,
          id_user: idUser,
          linea: 1
        }));
        this.openSnackBar('El usuario fue actualizado correctamente.');
      }

      this._location.back();
    }catch(error: any){
      if(error.error == undefined){
        this.openSnackBar('Ocurrió un error inesperado');
      }else{
        this.openSnackBar(error.error.msg);
      }
    }
  }

  return(){
    this._location.back();
  }

  openSnackBar(message: string){
    this._snackBar.open(message, "Cerrar", {
      duration: 5000
    });
  }

  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 }
  }

  getErrorMessage(control: string) {
    switch(control){
      case 'name':
        if(this.userForm.get('name')?.hasError('required')) return "Este campo es obligatorio.";
      break;
      case 'fApe':
        if(this.userForm.get('fApe')?.hasError('required')) return "Este campo es obligatorio.";
      break;
      case 'email':
        if(this.userForm.get('email')?.hasError('required')) return "Este campo es obligatorio.";
        if(this.userForm.get('email')?.hasError('email')) return "El correo no tiene un formáto válido.";
      break;
      case 'perf':
        if(this.userForm.get('perf')?.hasError('required')) return "Este campo es obligatorio.";
      break;
      case 'password':
        if(this.userForm.get('password')?.hasError('required')) return "Este campo es obligatorio.";
        if(this.userForm.get('password')?.hasError('minlength')) return "La contraseña debe tener al menos 8 caracteres.";
      break;
      case 'password_confirmation':
        if(this.userForm.get('password_confirmation')?.hasError('required')) return "Este campo es obligatorio.";
        if(this.userForm.get('password_confirmation')?.hasError('minlength')) return "La contraseña debe tener al menos 8 caracteres.";
        if(this.userForm.errors != null && this.userForm.errors!['notSame']) return "Las contraseñas no coinciden.";
      break;
    }
    
    return "A";
  }

  generatePass(){
    const ULET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    const LLET = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    const NUMS = [0, 1, 3, 4, 5, 6, 7, 8, 9];
    const CHAR = ['!', '#', '$', '%', '&', '(', ')', '=', '°', '*', '^', '{', '}', '[', ']', '-', '_', '?'];

    let password = "";
    for(var i = 0; i < 16; i++){
      let arraySelector = Math.floor(Math.random() * 4);
      switch(arraySelector){
        case 0:
          let mayusSelector = Math.floor(Math.random() * ULET.length);
          password += ULET[mayusSelector];
        break;
        case 1:
          let minusSelector = Math.floor(Math.random() * LLET.length);
          password += LLET[minusSelector];
        break;
        case 2:
          let numSelector = Math.floor(Math.random() * NUMS.length);
          password += NUMS[numSelector].toString();
        break;
        case 3:
          let charSelector = Math.floor(Math.random() * NUMS.length);
          password += CHAR[charSelector];
        break;
      }
    }

    this.userForm.controls['password'].setValue(password);
    this.userForm.controls['password_confirmation'].setValue(password);
  }

  goBack(steps: number){
    window.history.go(steps * -1);
  }
}

export class NotSamePasswordsMatcher implements ErrorStateMatcher{
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const invalidCtrl = !!(control?.invalid && control.parent?.dirty);
    const invalidParent = !!(control?.parent?.invalid && control.parent.dirty);

    return form?.form.controls['password'].value != form?.form.controls['password_confirmation'].value;
  }
}
