import { Component, OnInit } from '@angular/core';
import { UserAuth, UsersAuth } from '../../../interfaces/user-auths.interface';
import { MatTableDataSource } from '@angular/material/table';
import { FormBuilder, FormControl } from '@angular/forms';
import { SystemAdminService } from '../../../services/system-admin.service';
import { EncService } from '../../../services/enc.service';
import { SocketService } from '../../../services/socket.service';
import { UsersProfilesService } from '../../../services/users-profiles.service';
import { Router } from '@angular/router';
import { FunctionsService } from '../../../services/functions.service';
import { ResourcesService } from '../../../services/resources.service';
import { UserConsultResponse } from '../../../interfaces/user.interface';
import { lastValueFrom } from 'rxjs';
import { ProfileInterface } from '../../../interfaces/profile.interface';
import { PasswordFormatResponse } from '../../../interfaces/password-format.interface';
import { SessionsDurationsInterface } from '../../../interfaces/sessions-duration.interface';
import { ActiveSessionsNumberResponse } from '../../../interfaces/active-sessions-number.interface';
import { Permissions } from '../../../interfaces/permissions.interface';

@Component({
    selector: 'app-security-politics',
    templateUrl: './security-politics.component.html',
    styleUrl: './security-politics.component.css',
    standalone: false
})
export class SecurityPoliticsComponent implements OnInit {
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  users: UserAuth[] = [];

  passwordPatternEnabled: boolean;
  sessionsDurationEnabled: boolean;
  twoFactorAuthEnabled: boolean;
  activeSessionsNumberEnabled: boolean;

  politicsForm = this._formBuilder.group({
    enableMinLength: true,
    minLength: '8',
    enableUpperCase: true,
    minUpper: new FormControl({value: '1', disabled: false}),
    enableNumbers: true,
    minNumber: new FormControl({value: '1', disabled: false}),
    enableCharacters: true,
    minCharacters: new FormControl({value: '1', disabled: false})
  });

  sessionsForm = this._formBuilder.group({
    days: '1',
    hours: '0',
    minutes: '0',
    seconds: '0',
  });

  sessionsNumberForm = this._formBuilder.group({
    number: '3',
  });

  dataSourceAuth?: MatTableDataSource<UserAuth>;
  displayedColumnsAuth = ['ID', 'NAME', 'AUTH'];

  constructor(
    private _formBuilder: FormBuilder,
    private _systemAdminService: SystemAdminService,
    private _encService: EncService,
    private _socketService: SocketService,
    private _usersProfilesService: UsersProfilesService,
    private _router: Router,
    private _functionsService: FunctionsService,
    private _resourcesService: ResourcesService,
  ) {
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = "";
    this.passwordPatternEnabled = true;
    this.sessionsDurationEnabled = true;
    this.twoFactorAuthEnabled = true;
    this.activeSessionsNumberEnabled = true;
  }

  ngOnInit(): void {
    this.getAuthData();
    this._socketService.refreshPermissions().subscribe(async (profUpdEnc) => {
      try{
        let idUser = localStorage.getItem('idusuario')!;
        let usrInfo: UserConsultResponse = await lastValueFrom(this._usersProfilesService.getUser(idUser, idUser, 1));
        
        if(usrInfo.error){
          this._resourcesService.openSnackBar('ERR_NPE000: Ocurrió un error inesperado.');
        }else{
          let idProfDec = await this._encService.decrypt(usrInfo.response.PERFIL);
          let currentProfile = await this._encService.decrypt(localStorage.getItem('perfil')!);

          if(idProfDec != currentProfile){
            this._router.navigate(['/sam/home']);
            return;
          }
          
          let profileUpdated = await this._encService.decrypt(`${profUpdEnc}`);
          if(profileUpdated == currentProfile){
            let profile = localStorage.getItem('perfil')!;
            let profInfo: ProfileInterface = await lastValueFrom(this._usersProfilesService.getProfile(
              profile,
              idUser,
              1
            ));

            let permArr = await this._functionsService.processPermissions(profInfo.response.PERMISOS.permissions);
            let modPerm = permArr.filter(item => item.id == 'S002V01M01ADSI');
            if(modPerm.length > 0){
              let funPerm = modPerm[0].children.filter(item => item.id == 'S002V01F04POSE');
              if(funPerm.length > 0){
                let passwordPatternEnabled = funPerm[0].children.filter(item => item.id == 'S002V01P01PACO');
                if(passwordPatternEnabled.length > 0){
                  this.passwordPatternEnabled = passwordPatternEnabled[0].access > 0;
                }

                let sessionsDurationEnabled = funPerm[0].children.filter(item => item.id == 'S002V01P02DUSE');
                if(sessionsDurationEnabled.length > 0){
                  this.sessionsDurationEnabled = sessionsDurationEnabled[0].access > 0;
                }

                let twoFactorAuthEnabled = funPerm[0].children.filter(item => item.id == 'S002V01P03ADPA');
                if(twoFactorAuthEnabled.length > 0){
                  this.twoFactorAuthEnabled = twoFactorAuthEnabled[0].access > 0;
                }

                let activeSessionsNumberEnabled = funPerm[0].children.filter(item => item.id == 'S002V01P04NSAC');
                if(activeSessionsNumberEnabled.length > 0){
                  this.activeSessionsNumberEnabled = activeSessionsNumberEnabled[0].access > 0;
                }
              }
            }
          }
        }
      }catch(error: any){
        if(error.error == undefined){
          this._resourcesService.openSnackBar('ERR_PAD001: Ocurrió un error inesperado.');
        }else if(error.error.msg == undefined){
          this._resourcesService.openSnackBar('ERR_PAD002: Ocurrió un error inesperado.');
        }else{
          this._resourcesService.openSnackBar(`ERR_PAD003: ${error.error.msg}`);
        }
      }
    });
  }

  async getAuthData(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let userAuths: UsersAuth = await lastValueFrom(this._systemAdminService.getTwoStepsAuth(idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        let idUserDec = await this._encService.decrypt(idUser);
        let userAuthsArr: UserAuth[] = [];

        for(const user of userAuths.response){
          let idDec = await this._encService.decrypt(user.IDUSUARIO);
          if(idDec != idUserDec){
            let usr: UserAuth = {
              IDUSUARIO: idDec,
              NOMBREUSUARIO: user.NOMBREUSUARIO,
              AUTHENABLED: user.AUTHENABLED
            };

            userAuthsArr.push(usr);
          }
        }
        
        this.users = userAuthsArr;
        this.dataSourceAuth = new MatTableDataSource(userAuthsArr);
        this.getPwdData();
      }
    }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 getPwdData(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let pwdFormat: PasswordFormatResponse = await lastValueFrom(this._systemAdminService.getPasswordFormat(idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        this.politicsForm.controls.minLength.setValue(`${pwdFormat.response.password_format.min_length}`);
        this.politicsForm.controls.enableUpperCase.setValue(pwdFormat.response.password_format.upper_enabled);
        this.politicsForm.controls.minUpper.setValue(`${pwdFormat.response.password_format.min_upper}`);
  
        if(!pwdFormat.response.password_format.upper_enabled){
          this.politicsForm.controls.minUpper.disable();
        }
  
        this.politicsForm.controls.enableNumbers.setValue(pwdFormat.response.password_format.number_enabled);
        this.politicsForm.controls.minNumber.setValue(`${pwdFormat.response.password_format.min_number}`);
  
        if(!pwdFormat.response.password_format.number_enabled){
          this.politicsForm.controls.minNumber.disable();
        }
  
        this.politicsForm.controls.enableCharacters.setValue(pwdFormat.response.password_format.chars_enabled);
        this.politicsForm.controls.minCharacters.setValue(`${pwdFormat.response.password_format.min_chars}`);
  
        if(!pwdFormat.response.password_format.chars_enabled){
          this.politicsForm.controls.minCharacters.disable();
        }
        
        this.getSessionsData();
      }
    }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 getSessionsData(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let sessionsDuration: SessionsDurationsInterface = await lastValueFrom(this._systemAdminService.getSessionsDuration(idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        this.sessionsForm.controls.days.setValue(`${sessionsDuration.response.sessions_duration.days}`);
        this.sessionsForm.controls.hours.setValue(`${sessionsDuration.response.sessions_duration.hours}`);
        this.sessionsForm.controls.minutes.setValue(`${sessionsDuration.response.sessions_duration.minutes}`);
        this.sessionsForm.controls.seconds.setValue(`${sessionsDuration.response.sessions_duration.seconds}`);
      
        this.getActiveSessionsNumber();
      }
    }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 getActiveSessionsNumber(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let activeSessionsNumber: ActiveSessionsNumberResponse = await lastValueFrom(this._systemAdminService.getActiveSessionsNumber(idUser, 1));

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

      if(!this.hasError){
        this.sessionsNumberForm.controls.number.setValue(`${activeSessionsNumber.response.active_sessions_number}`);

        let permissionsEnc = localStorage.getItem('permisos');
        let permissionsDec = await this._encService.decrypt(permissionsEnc!);
        let permissionsArr: Permissions = JSON.parse(permissionsDec);

        let modPerm = permissionsArr.permissions.filter(item => item.id == 'S002V01M01ADSI')[0];
        let funPerm = modPerm.children.filter(item => item.id == 'S002V01F04POSE')[0];

        this.passwordPatternEnabled = funPerm.children.filter(item => item.id == 'S002V01P01PACO')[0].access > 0;
        this.sessionsDurationEnabled = funPerm.children.filter(item => item.id == 'S002V01P02DUSE')[0].access > 0;
        this.twoFactorAuthEnabled = funPerm.children.filter(item => item.id == 'S002V01P03ADPA')[0].access > 0;
        this.activeSessionsNumberEnabled = funPerm.children.filter(item => item.id == 'S002V01P04NSAC')[0].access > 0;
      }

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

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

  editMinLength(action: number){
    let minLengthStr = this.politicsForm.getRawValue().minLength;
    let minLength = parseInt(minLengthStr!);
    if(action == 0){
      if(minLength > 8){
        minLength--;
        this.politicsForm.controls.minLength.setValue(`${minLength}`);
      }
    }else{
      if(minLength < 30){
        minLength++;
        this.politicsForm.controls.minLength.setValue(`${minLength}`);
      }
    }
  }

  disableMinUpper(){
    let isDisabled = this.politicsForm.controls.minUpper.disabled;
    if(isDisabled){
      this.politicsForm.controls.minUpper.enable();
    }else{
      this.politicsForm.controls.minUpper.disable();
    }
  }

  editMinUpper(action: number){
    let minUpperStr = this.politicsForm.getRawValue().minUpper;
    let minUpper = parseInt(minUpperStr!);
    if(action == 0){
      if(minUpper > 1){
        minUpper--;
        this.politicsForm.controls.minUpper.setValue(`${minUpper}`);
      }
    }else{
      if(minUpper < 10){
        minUpper++;
        this.politicsForm.controls.minUpper.setValue(`${minUpper}`);
      }
    }
  }

  disableMinNumber(){
    let isDisabled = this.politicsForm.controls.minNumber.disabled;
    if(isDisabled){
      this.politicsForm.controls.minNumber.enable();
    }else{
      this.politicsForm.controls.minNumber.disable();
    }
  }

  editMinNumber(action: number){
    let minNumberStr = this.politicsForm.getRawValue().minNumber;
    let minNumber = parseInt(minNumberStr!);
    if(action == 0){
      if(minNumber > 1){
        minNumber--;
        this.politicsForm.controls.minNumber.setValue(`${minNumber}`);
      }
    }else{
      if(minNumber < 10){
        minNumber++;
        this.politicsForm.controls.minNumber.setValue(`${minNumber}`);
      }
    }
  }

  disableMinCharacters(){
    let isDisabled = this.politicsForm.controls.minCharacters.disabled;
    if(isDisabled){
      this.politicsForm.controls.minCharacters.enable();
    }else{
      this.politicsForm.controls.minCharacters.disable();
    }
  }

  editMinCharacters(action: number){
    let minCharactersStr = this.politicsForm.getRawValue().minCharacters;
    let minCharacters = parseInt(minCharactersStr!);
    if(action == 0){
      if(minCharacters > 1){
        minCharacters--;
        this.politicsForm.controls.minCharacters.setValue(`${minCharacters}`);
      }
    }else{
      if(minCharacters < 10){
        minCharacters++;
        this.politicsForm.controls.minCharacters.setValue(`${minCharacters}`);
      }
    }
  }

  async savePaswordFormat(){
    try{
      var passwordForm = new FormData();
      let config = this.politicsForm.getRawValue();
      let idUser = localStorage.getItem('idusuario');

      passwordForm.append('id_user', idUser!);
      passwordForm.append('linea', '1');
      passwordForm.append('min_length', config.minLength!);
      passwordForm.append('upper_enabled', config.enableUpperCase ? '1' : '0');
      passwordForm.append('min_upper', config.minUpper!);
      passwordForm.append('number_enabled', config.enableNumbers ? '1' : '0');
      passwordForm.append('min_number', config.minNumber!);
      passwordForm.append('chars_enabled', config.enableCharacters ? '1' : '0');
      passwordForm.append('min_chars', config.minCharacters!);

      await lastValueFrom(this._systemAdminService.savePasswordFormat(passwordForm));

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

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

      this._resourcesService.openSnackBar(msg);
    }
  }

  editDays(action: number){
    let daysStr = this.sessionsForm.getRawValue().days;
    let days = parseInt(daysStr!);
    if(action == 0){
      if(days > 0){
        days--;
        this.sessionsForm.controls.days.setValue(`${days}`);

        let hoursStr = this.sessionsForm.getRawValue().hours!;
        let hours = parseInt(hoursStr);

        if(days == 0 && hours == 0){
          this.sessionsForm.controls['hours'].setValue('1');
          this._resourcesService.openSnackBar('La duración mínima de las sesiones debe ser de 1 hora.');
        }
      }
    }else{
      if(days < 30){
        days++;
        this.sessionsForm.controls.days.setValue(`${days}`);
      }
    }
  }

  editHours(action: number){
    let hoursStr = this.sessionsForm.getRawValue().hours;
    let hours = parseInt(hoursStr!);
    if(action == 0){
      if(hours > 0){
        let daysStr = this.sessionsForm.getRawValue().days;
        let days = parseInt(daysStr!);
        if(days == 0 && hours == 1){
          this._resourcesService.openSnackBar('La duración mínima de las sesiones debe ser de 1 hora.');
          return;
        }

        hours--;
        this.sessionsForm.controls.hours.setValue(`${hours}`);
      }
    }else{
      if(hours < 23){
        hours++;
        this.sessionsForm.controls.hours.setValue(`${hours}`);
      }
    }
  }

  editMinutes(action: number){
    let minutesStr = this.sessionsForm.getRawValue().minutes;
    let minutes = parseInt(minutesStr!);
    if(action == 0){
      if(minutes > 0){
        minutes--;
        this.sessionsForm.controls.minutes.setValue(`${minutes}`);
      }
    }else{
      if(minutes < 59){
        minutes++;
        this.sessionsForm.controls.minutes.setValue(`${minutes}`);
      }
    }
  }

  editSeconds(action: number){
    let secondsStr = this.sessionsForm.getRawValue().seconds;
    let seconds = parseInt(secondsStr!);
    if(action == 0){
      if(seconds > 0){
        seconds--;
        this.sessionsForm.controls.seconds.setValue(`${seconds}`);
      }
    }else{
      if(seconds < 59){
        seconds++;
        this.sessionsForm.controls.seconds.setValue(`${seconds}`);
      }
    }
  }

  async saveSessionsDuration(){
    try{
      var passwordForm = new FormData();
      let config = this.sessionsForm.getRawValue();
      let idUser = localStorage.getItem('idusuario');

      passwordForm.append('id_user', idUser!);
      passwordForm.append('linea', '1');
      passwordForm.append('days', config.days!);
      passwordForm.append('hours', config.hours!);
      passwordForm.append('minutes', config.minutes!);
      passwordForm.append('seconds', config.seconds!);

      await lastValueFrom(this._systemAdminService.saveSessionsDuration(passwordForm));

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

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

      this._resourcesService.openSnackBar(msg);
    }
  }

  async changeStatus(index: number){
    try{
      let item = this.users[index];
      let usersAux = this.users;
      
      item.AUTHENABLED = !item.AUTHENABLED;
      this.users = [];
  
      usersAux.forEach(user => {
        if(user.IDUSUARIO == item.IDUSUARIO){
          this.users.push(item);
        }else{
          this.users.push(user);
        }
      });
  
      this.dataSourceAuth = new MatTableDataSource(this.users);
      let usrEnc = await this._encService.encrypt(item.IDUSUARIO);
      let idUser = localStorage.getItem('idusuario');

      await lastValueFrom(this._systemAdminService.setTwoStepsAuth({
        id_user: idUser,
        usuario: usrEnc,
        factor_doble: item.AUTHENABLED ? 'Si' : 'No',
        linea: 1
      }));
    }catch(error: any){
      let msg = '';
      if(error.error == undefined){
        msg = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        msg = 'Ocurrió un error inesperado.';
      }else{
        msg = error.error.msg;
      }

      this._resourcesService.openSnackBar(msg);
    }
  }

  editNumber(action: number){
    let numStr = this.sessionsNumberForm.getRawValue().number;
    let num = parseInt(numStr!);
    if(action == 0){
      if(num > 1){
        num--;
        this.sessionsNumberForm.controls.number.setValue(`${num}`);
      }
    }else{
      if(num < 5){
        num++;
        this.sessionsNumberForm.controls.number.setValue(`${num}`);
      }
    }
  }

  async saveActiveSessionsNumber(){
    try{
      var passwordForm = new FormData();
      let config = this.sessionsNumberForm.getRawValue();
      let idUser = localStorage.getItem('idusuario');

      passwordForm.append('id_user', idUser!);
      passwordForm.append('linea', '1');
      passwordForm.append('sessions', config.number!);

      await lastValueFrom(this._systemAdminService.saveActiveSessionsNumber(passwordForm));

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

      this._socketService.enabledSessionsUpdated(config.number!);
      this.getAuthData();
    }catch(error: any){
      let msg = '';
      if(error.error == undefined){
        msg = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        msg = 'Ocurrió un error inesperado.';
      }else{
        msg = error.error.msg;
      }

      this._resourcesService.openSnackBar(msg);
    }
  }
}
