import { SocketService } from './../../../../services/socket.service';
import { ProfileInterface } from './../../../../interfaces/profile.interface';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ErrorStateMatcher } from '@angular/material/core';
import { UsersProfilesService } from './../../../../services/users-profiles.service';
import { MenusInterface } from './../../../../interfaces/menus.interface';
import { PermissionsResponseInterface, PermissionsInterface } from './../../../../interfaces/permissions.interface';
import { EncService } from './../../../../services/enc/enc.service';
import { SubmodulesResponse } from './../../../../interfaces/submodules.interface';
import { lastValueFrom } from 'rxjs';
import { ModulesInterface } from './../../../../interfaces/modules.interface';
import { ModulesService } from './../../../../services/modules.service';
import { FormGroup, FormControl, Validators, AbstractControl, FormGroupDirective, NgForm } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-new-profile',
  templateUrl: './new-profile.component.html',
  styleUrls: ['./new-profile.component.css']
})
export class NewProfileComponent implements OnInit {
  tituloCard: string;
  action: string;
  profileID?: number;
  permissions: PermissionsInterface[];

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

  constructor(
    private router: Router,
    private _usersProfilesService: UsersProfilesService,
    private _el: ElementRef,
    private _snackBar: MatSnackBar,
    private _location: Location,
    private _activatedRoute: ActivatedRoute,
    private _encService: EncService,
    private _socketService: SocketService
  ) { 
    this.tituloCard = "";
    this.action = "";
    
    this.permissions = [];
  }

  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._activatedRoute.queryParams.subscribe(params => {
      if(this.action != 'crear'){
        let info = params['info'];
        
        if(info == undefined){
          this.openSnackbar('No se encontró información del perfil en la ruta.');
          this.back();
        }else{
          this._encService.desencriptar(info).then((infoDec) => {
            let infoObj = JSON.parse(infoDec);
            this.tituloCard += ` - ${infoObj.profileName}`
            this.getProfile(infoObj.profile);
          });
        }

        if(this.action == 'detalles'){
          this.profileName.disable();
          this.isDetails = true;
        }
      }else{
        this.getPermissions()
      }
    });
  }

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

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

  async getPermissions(){
    try{
      let idEnc = localStorage.getItem('idusuario');
      let idShort = await lastValueFrom(this._encService.shortEncrypt(idEnc!));
      
      let permissions: PermissionsResponseInterface = await lastValueFrom(this._usersProfilesService.getInitialPermissions(idShort.response.encrypted, 1));
      
      this.permissions = permissions.response.permissions;
      this.isLoading = false;
      this.hasError = permissions.error;
      this.errorStr = permissions.msg;
    }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;
      }
    }
  }

  async getProfile(id: number){
    try{
      let idProf = await this._encService.encriptar(`${id}`);
      let profShort = await lastValueFrom(this._encService.shortEncrypt(idProf));
      console.log(profShort);
      
      let idEnc = localStorage.getItem('idusuario');
      let idShort = await lastValueFrom(this._encService.shortEncrypt(idEnc!));
      
      let profile: ProfileInterface = await lastValueFrom(this._usersProfilesService.getProfile(
        profShort.response.encrypted,
        idShort.response.encrypted, 
        1
      ));

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

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

        this.profileName.setValue(profile.response.NOMBREPERFIL);
        this.profileID = profile.response.IDPERFIL;
      }
    }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;
      }
    }
  }

  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 == module.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;
    }
  }

  openSnackbar(msg: string){
    this._snackBar.open(msg, 'Cerrar', {
      duration: 5000
    });
  }

  async save(){
    if(!this.profileName.valid){
      this.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.openSnackbar('Perfil insertado correctamente.');
        }else if(this.action == 'editar'){
          let perfEnc = await this._encService.encriptar(`${this.profileID!}`);
          
          await lastValueFrom(this._usersProfilesService.updateProfile({
            id: perfEnc,
            permissions: permissionsStr,
            id_user: localStorage.getItem('idusuario'),
            name: profileName,
            linea: 1
          }));

          //let perfEnc = await this._encService.encriptar(`${this.profileID}`);
          this.openSnackbar('Perfil actualizado correctamente.');
          //this._socketService.profileUpdated(perfEnc);
        }
        this._location.back();
      }catch(error: any){
        console.log(error);
        
        let msg = "";
        if(error.error == undefined){
          msg = 'Ocurrió un error inesperado.';
        }else{
          msg = error.error.msg;
        }

        this.openSnackbar(msg);
      }
    }
  }

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

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