import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormControl, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
import { Permissions, PermissionsInterface, PermissionsResponseInterface } from '../../../../interfaces/permissions.interface';
import { ActivatedRoute, Router } from '@angular/router';
import { UsersProfilesService } from '../../../../services/users-profiles.service';
import { EncService } from '../../../../services/enc.service';
import { SocketService } from '../../../../services/socket.service';
import { ResourcesService } from '../../../../services/resources.service';
import { FunctionsService } from '../../../../services/functions.service';
import { ProfileInterface } from '../../../../interfaces/profile.interface';
import { lastValueFrom } from 'rxjs';
import { UserConsultResponse } from '../../../../interfaces/user.interface';

const ID_MODULE = "S002V01M02USPE";
@Component({
    selector: 'app-new-profile',
    templateUrl: './new-profile.component.html',
    styleUrl: './new-profile.component.css',
    standalone: false
})
export class NewProfileComponent implements OnInit {
  tituloCard: string;
  action: string;
  profileID!: string;
  permissions: PermissionsInterface[];

  isLoading = true;
  hasError = false;
  isDetails = false;
  errorStr = "";
  errorMatcher = new MatchErrors();
  profileName = new FormControl('', [Validators.required, Validators.maxLength(50), Validators.minLength(8)])

  realTimeUpdateEnabled: boolean;

  constructor(
    private _router: Router,
    private _usersProfilesService: UsersProfilesService,
    private _activatedRoute: ActivatedRoute,
    private _encService: EncService,
    private _socketService: SocketService,
    private _resourcesService: ResourcesService,
    private _functionsService: FunctionsService,
  ) { 
    this._functionsService.consultModuleStatus(ID_MODULE);
    this.tituloCard = "";
    this.action = "";
    
    this.permissions = [];
    this.realTimeUpdateEnabled = false;
  }

  ngOnInit(): void {
    let current = this._router.url;
    let arrRoute = current.split("/");
    
    this.action = arrRoute[arrRoute.length - 1];
    this.action = this.action.split("?")[0];
    
    this.tituloCard = `${this.capitalize(arrRoute[arrRoute.length - 1].split("?")[0])} perfil`;
    this.init();
  }

  capitalize(str: string){
    let arr = str.split("");
    arr[0] = arr[0].toUpperCase();
    let capitalized = "";
    arr.forEach(l => capitalized += l);
    return capitalized;
  }

  async init(){
    let permissionsEnc = localStorage.getItem('permisos');
    let permissionsDec = '';
    if(permissionsEnc == '' || permissionsEnc == undefined || permissionsEnc == null){
      permissionsDec = '[]';
    }else{
      permissionsDec = await this._encService.decrypt(permissionsEnc!);
    }

    let permissionsArr: Permissions = JSON.parse(permissionsDec);
    if(permissionsArr.permissions != undefined){
      let modPerm = permissionsArr.permissions.filter(item => item.id == 'S002V01M02USPE');
      if(modPerm.length > 0){
        let subPerm = modPerm[0].children.filter(item => item.id == 'S002V01S02GEPE');
        if(subPerm.length > 0){
          let realTimeUpdateEnabled = subPerm[0].children.filter(item => item.id == 'S002V01F02APTR');
          if(realTimeUpdateEnabled.length > 0){
            this.realTimeUpdateEnabled = realTimeUpdateEnabled[0].access > 0;
          }
        }
      }
    }

    this._activatedRoute.queryParams.subscribe(params => {
      if(this.action != 'crear'){
        let info = params['info'];

        if(this.action == 'detalles'){
          this.profileName.disable();
          this.isDetails = true;
        }
        
        if(info == undefined){
          this._resourcesService.openSnackBar('No se encontró información del perfil en la ruta.');
          this.goBack(1);
        }else{
          this.getProfile(info);
        }
      }else{
        this.getPermissions();
      }
    });
    
    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 == 'S002V01M02USPE');
            if(modPerm.length > 0){
              let subPerm = modPerm[0].children.filter(item => item.id == 'S002V01S02GEPE');
              if(subPerm.length > 0){
                let realTimeUpdateEnabled = subPerm[0].children.filter(item => item.id == 'S002V01F02APTR');
                if(realTimeUpdateEnabled.length > 0){
                  this.realTimeUpdateEnabled = realTimeUpdateEnabled[0].access > 0;
                }
              }
            }
          }
        }
      }catch(error: any){
        if(error.error == undefined){
          this._resourcesService.openSnackBar('ERR_NPE001: Ocurrió un error inesperado.');
        }else if(error.error.msg == undefined){
          this._resourcesService.openSnackBar('ERR_NPE002: Ocurrió un error inesperado.');
        }else{
          this._resourcesService.openSnackBar(`ERR_NPE003: ${error.error.msg}`);
        }
      }
    });

    this._socketService.refreshModules().subscribe(async () => this._functionsService.consultModuleStatus(ID_MODULE));
  }

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

  async getProfile(infoEnc: string){
    try{
      let infoDec = await this._encService.decrypt(infoEnc);
      let infoObj = JSON.parse(infoDec);
      
      let idProf = await this._encService.encrypt(`${infoObj.profile}`);
      let idEnc = localStorage.getItem('idusuario')!;
      let profile: ProfileInterface = await lastValueFrom(this._usersProfilesService.getProfile(
        idProf,
        idEnc, 
        1
      ));

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

      if(!this.hasError){
        let processedPermissions = await this.processPermissions(profile.response.PERMISOS.permissions);
        this.permissions = processedPermissions;

        this.profileName.setValue(profile.response.NOMBREPERFIL);
        this.profileID = profile.response.IDPERFIL;
      }

      this.isLoading = false;
    }catch(error: any){
      this.isLoading = false;
      this.hasError = true;
      
      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;
      }
    }
  }

  private async processPermissions(children: PermissionsInterface[]): Promise<PermissionsInterface[]>{
    let childrenArr: PermissionsInterface[] = [];
    for(const child of children){
      child.id = await this._encService.decrypt(child.id);
      if(child.children != undefined && child.children.length > 0){
        let processedChildren = await this.processPermissions(child.children);
        child.children = processedChildren;
      }

      childrenArr.push(child);
    }

    return childrenArr;
  }

  async getPermissions(){
    try{
      let idEnc = localStorage.getItem('idusuario')!;
      let permissions: PermissionsResponseInterface = await lastValueFrom(this._usersProfilesService.getInitialPermissions(idEnc, 1));
      
      this.hasError = permissions.error;
      this.errorStr = permissions.msg;

      if(!this.hasError){
        this.permissions = permissions.response.permissions;
      }

      this.isLoading = false;
    }catch(error: any){
      this.hasError = true;
      this.isLoading = false;
      this.errorStr = "";

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

  enableModule(id:string){
    if(!this.isDetails){
      let permissionsAux: PermissionsInterface[] = [];
      this.permissions.forEach(module => {
        if(module.id == id){
          let newAccess = module.access == 0 ? 2 : 0;
  
          module.children.forEach(submodule => {
            this.enableSubmodule(id, submodule.id, newAccess);
          });
  
          let moduleAux: PermissionsInterface = {
            id: module.id,
            name: module.name,
            access: newAccess,
            children: module.children
          };
  
          permissionsAux.push(moduleAux);
        }else{
          permissionsAux.push(module);
        }
      });
  
      this.permissions = permissionsAux;
    }
  }

  enableSubmodule(idMod: string, idSub: string, parentAccess: number = -1){
    if(!this.isDetails){
      let module = this.permissions.filter(module => module.id == idMod)[0];
      let modIndex = this.permissions.indexOf(module);
  
      let submodulesAux: PermissionsInterface[] = [];
      this.permissions[modIndex].children.forEach(submodule => {
        if(submodule.id == idSub){
          let newAccess = submodule.access == 0 ? 2 : 0;
          if(parentAccess != -1){
            newAccess = parentAccess;
          }
  
          submodule.children.forEach(func => {
            this.enableFunction(idMod, idSub, func.id, newAccess);
          });
  
          let submoduleAux: PermissionsInterface = {
            id: submodule.id,
            name: submodule.name,
            access: newAccess,
            children: submodule.children
          };
  
          submodulesAux.push(submoduleAux);
        }else{
          submodulesAux.push(submodule);
        }
      });
      
      let submodulesEnabled = 0;
      let submodulesPartialEnabled = 0;
      submodulesAux.forEach(submodule => {
        if(submodule.access == 2) submodulesEnabled++;
        if(submodule.access == 1) submodulesPartialEnabled++;
      });
  
      let newAccess = 0;
      if(submodulesEnabled == module.children.length){
        newAccess = 2;
      }else if(submodulesEnabled > 0 || submodulesPartialEnabled > 0){
        newAccess = 1;
      }
  
      this.permissions[modIndex].access = newAccess;
      this.permissions[modIndex].children = submodulesAux;
    }
  }

  enableFunction(idMod: string, idSub: string, idFun: string, parentAccess: number = -1){
    if(!this.isDetails){
      let module = this.permissions.filter(module => module.id == idMod)[0];
      let moduleIndex = this.permissions.indexOf(module);
  
      let submodule = module.children.filter(submodule => submodule.id == idSub)[0];
      let submoduleIndex = module.children.indexOf(submodule);
  
      let functionsAux: PermissionsInterface[] = [];
      this.permissions[moduleIndex].children[submoduleIndex].children.forEach(func => {
        if(func.id == idFun){
          let newAccess = func.access == 0 ? 2 : 0;
  
          if(parentAccess != -1){
            newAccess = parentAccess;
          }
  
          if(func.children != undefined){
            if(func.children.length > 0){
              func.children.forEach(screen => {
                this.enableScren(idMod, idSub, idFun, screen.id, newAccess);
              });
            }
          }
  
          let functionAux: PermissionsInterface = {
            id: func.id,
            name: func.name,
            access: newAccess,
            children: func.children
          };
  
          functionsAux.push(functionAux);
        }else{
          functionsAux.push(func);
        }
      });
  
      let functionsEnabled = 0;
      let functionsPartialEnabled = 0;
      functionsAux.forEach(func => {
        if(func.access == 2) functionsEnabled++;
        if(func.access == 1) functionsPartialEnabled++;
      });
  
      let newSubmoduleAccess = 0;
      if(functionsEnabled == submodule.children.length){
        newSubmoduleAccess = 2;
      }else if(functionsEnabled > 0 || functionsPartialEnabled > 0){
        newSubmoduleAccess = 1;
      }
  
      this.permissions[moduleIndex].children[submoduleIndex].children = functionsAux;
      this.permissions[moduleIndex].children[submoduleIndex].access = newSubmoduleAccess;
      
      let submodulesEnabled = 0;
      let submodulesPartialEnabled = 0;
      this.permissions[moduleIndex].children.forEach(submod => {
        if(submod.access == 2) submodulesEnabled++;
        if(submod.access == 1) submodulesPartialEnabled++;
      });
  
      let newAccess = 0;
      if(submodulesEnabled == module.children.length){
        newAccess = 2;
      }else if(submodulesEnabled > 0 || submodulesPartialEnabled > 0){
        newAccess = 1;
      }
  
      this.permissions[moduleIndex].access = newAccess;
    }
  }

  enableScren(idMod: string, idSub: string, idFun: string, idScr: string, parentAccess: number = -1){
    if(!this.isDetails){
      let module = this.permissions.filter(module => module.id == idMod)[0];
      let moduleIndex = this.permissions.indexOf(module);
  
      let submodule = module.children.filter(submodule => submodule.id == idSub)[0];
      let submoduleIndex = module.children.indexOf(submodule);
  
      let func = submodule.children.filter(func => func.id == idFun)[0];
      let funcIndex = submodule.children.indexOf(func);
      
      let screensAux: PermissionsInterface[] = [];
      this.permissions[moduleIndex].children[submoduleIndex].children[funcIndex].children.forEach(screen => {
        if(screen.id == idScr){
          let newAccess = screen.access == 0 ? 2 : 0;
  
          if(parentAccess != -1){
            newAccess = parentAccess;
          }
  
          let screenAux: PermissionsInterface = {
            id: screen.id,
            name: screen.name,
            access: newAccess,
            children: screen.children
          };
  
          screensAux.push(screenAux);
        }else{
          screensAux.push(screen);
        }
      });
      
      let screensEnabled = 0;
      let screensPartialEnabled = 0;
      screensAux.forEach(screen => {
        if(screen.access == 2) screensEnabled++;
        if(screen.access == 1) screensPartialEnabled++;
      });
  
      let newFunctionAccess = 0;
      if(screensEnabled == func.children.length){
        newFunctionAccess = 2;
      }else if(screensEnabled > 0 || screensPartialEnabled > 0){
        newFunctionAccess = 1;
      }
  
      this.permissions[moduleIndex].children[submoduleIndex].children[funcIndex].children = screensAux;
      this.permissions[moduleIndex].children[submoduleIndex].children[funcIndex].access = newFunctionAccess;
  
      let functionsEnabled = 0;
      let functionsPartialEnabled = 0;
      this.permissions[moduleIndex].children[submoduleIndex].children.forEach(func => {
        if(func.access == 2) functionsEnabled++;
        if(func.access == 1) functionsPartialEnabled++;
      });
  
      let newSubmoduleAccess = 0;
      if(functionsEnabled == submodule.children.length){
        newSubmoduleAccess = 2;
      }else if(functionsEnabled > 0 || functionsPartialEnabled > 0){
        newSubmoduleAccess = 1;
      }
  
      this.permissions[moduleIndex].children[submoduleIndex].access = newSubmoduleAccess;
      
      let submodulesEnabled = 0;
      let submodulesPartialEnabled = 0;
      this.permissions[moduleIndex].children.forEach(submod => {
        if(submod.access == 2) submodulesEnabled++;
        if(submod.access == 1) submodulesPartialEnabled++;
      });
  
      let newAccess = 0;
      if(submodulesEnabled == module.children.length){
        newAccess = 2;
      }else if(submodulesEnabled > 0 || submodulesPartialEnabled > 0){
        newAccess = 1;
      }
  
      this.permissions[moduleIndex].access = newAccess;
    }
  }

  getAccessText(access: number): string{
    if(access == 0){
      return "Inhabilitado";
    }else if(access == 1){
      return "Parcialmente habilitado";
    }else{
      return "Habilitado";
    }
  }

  hasChildren(id: string): boolean{
    let module = this.permissions.filter(mod => mod.id == id)[0];

    if(module.children == null || module.children == undefined){
      return false;
    }else if(module.children.length == 0){
      return false;
    }else{
      return true;
    }
  }

  async save(){
    if(!this.profileName.valid){
      this._resourcesService.openSnackBar('Ingresa los campos requeridos para continuar.');
      this.profileName.markAllAsTouched();
    }else{
      let profileName = this.profileName.value;
      let permissionsObj = {
        permissions: this.permissions,
      }

      let permissionsStr = JSON.stringify(permissionsObj);

      try{
        if(this.action == 'crear'){
          await lastValueFrom(this._usersProfilesService.newProfile({
            name: profileName,
            permissions: permissionsStr,
            id_user: localStorage.getItem('idusuario'),
            linea: 1
          }));
          this._resourcesService.openSnackBar('Perfil insertado correctamente.');
        }else if(this.action == 'editar'){
          await lastValueFrom(this._usersProfilesService.updateProfile({
            id: this.profileID!,
            permissions: permissionsStr,
            id_user: localStorage.getItem('idusuario'),
            name: profileName,
            linea: 1
          }));

          this._resourcesService.openSnackBar('Perfil actualizado correctamente.');
          this._socketService.profileUpdated(this.profileID!);
        }

        this.goBack(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);
      }
    }
  }
}

export class MatchErrors implements ErrorStateMatcher{
  isErrorState(control: AbstractControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}
