import { MatSnackBar } from '@angular/material/snack-bar';
import { UserConsultResponse } from './../../interfaces/user.interface';
import { MyProfileComponent } from './my-profile/my-profile.component';
import { MaintenanceStatusResponse } from './../../interfaces/maintenance-status.interface';
import { SystemAdminService } from './../../services/system-admin.service';
import { BasicAlertComponent } from './../resources/dialogs/basic-alert/basic-alert.component';
import { AdviceAlertComponent } from './advice-alert/advice-alert.component';
import { Advice, AdviceResponse } from './../../interfaces/advice.interface';
import { AdvicesService } from './../../services/advices.service';
import { NavItem } from './../../interfaces/nav-item.interface';
import { NestedMenuInterface, MenuModules } from './../../interfaces/nested-menu.interface';
import { lastValueFrom } from 'rxjs';
import { UsersProfilesService } from './../../services/users-profiles.service';
import { SocketService } from './../../services/socket.service';
import { EncService } from './../../services/enc/enc.service';
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { LoginDataService } from 'src/app/services/login/login-data.service';
import { ProfileInterface } from 'src/app/interfaces/profile.interface';
import { Permissions } from './../../interfaces/permissions.interface';
import { AlertComponent } from '../resources/dialogs/alert/alert.component';
import { ModulesService } from 'src/app/services/modules.service';
import { ResourcesService } from 'src/app/services/resources/resources.service';
import { CataloguesService } from 'src/app/services/catalogues.service';
import { HttpErrorResponse } from '@angular/common/http';
import { CatalogueCoins, CatalogueCoinsDocument, CataloguePaymentMethod, CataloguePaymentMethodDocument, ResponseDataCatalogueCoins, ResponseDataCataloguePaymentMethod } from 'src/app/interfaces/catalogue.interface';

@Component({
  selector: 'app-template',
  templateUrl: './template.component.html',
  styleUrls: ['./template.component.css']
})
export class TemplateComponent implements OnInit {
  nestedMenu: MenuModules[];
  navItems: NavItem[];
  menuItems: MenuModules[];

  showFiller = false;
  panelOpenState = false;
  public screen_small = false;

  maintenanceActivated = false;
  maintenanceMode = false;
  isLoading = true;
  minutesLeft = 5;
  secondsLeft = 0;
  errorsCont = 0;
  timeLeft = "5:00";

  userName = "";

  public title:string = 'Sistema de Ayuda al Manteniemiento L1';

  modulesActivated = false;

  constructor(
    public resourcesService: ResourcesService,
    private _router: Router,
    private _loginDataService: LoginDataService,
    private _encService: EncService,
    private _socketService: SocketService,
    private _profilesService: UsersProfilesService,
    private _dialg: MatDialog,
    private _modulesService: ModulesService,
    private _advicesService: AdvicesService,
    private _sysAdminService: SystemAdminService,
    private _snackBar: MatSnackBar,
    private _cataloguesService: CataloguesService,
    
  ) {
    this.navItems = [];
    this.menuItems = [];
    this.nestedMenu = [];
  }

  async ngOnInit() {
    this.isLoading = true;
    await this.init();
    await this.checkCatalogues();

    this.isLoading = false;

  }

  async init(){
    try{
      //Ejecutar el tamaño de la pantalla inicial
      this.onResize();
      //Consultar el estado del modo mantenimiento
      let idUser = localStorage.getItem('idusuario');
      let maintenanceStatus: MaintenanceStatusResponse = await lastValueFrom(this._sysAdminService.getMaintenanceStatus(idUser!, 1));

      this.maintenanceMode = maintenanceStatus.response.activated;
      
      //Obtención del menú de módulos, submódulos, funciones y pantallas del SAM
      let menu: NestedMenuInterface = await lastValueFrom(this._modulesService.getMenu(idUser!, 1));
      //Lectura, decodificación y procesamiento de los permisos del usuario
      let permissions = localStorage.getItem('permisos');
      let permStr = await this._encService.decrypt(permissions!);
      let permObj: Permissions = JSON.parse(permStr);
      menu.response.forEach(item => {
        let idMod = item.IDMODULO;
        let modPerm = permObj.permissions.filter(item2 => item2.id == idMod)[0];
        let access = modPerm.access;
        if(access > 0){
          this.menuItems.push(item);
        }
      });
      
      //Conexiones a los eventos del Socket
      if (window.innerWidth <= 616) {
        this.screen_small = false;
      }else if(window.innerWidth > 616){
        this.screen_small = true;
      }
  
      this._socketService.refreshPermissions().subscribe(async (profUpdEnc) => {
        let idUser = localStorage.getItem('idusuario')!;
        let usrInfo: UserConsultResponse = await lastValueFrom(this._profilesService.getUser(idUser, idUser, 1));
        let currentProfile = await this._encService.decrypt(localStorage.getItem('perfil')!);

        if(parseInt(currentProfile) != usrInfo.response.PERFIL){
          let perfEnc = await this._encService.encrypt(`${usrInfo.response.PERFIL}`);
          localStorage.setItem('perfil', perfEnc);
          currentProfile = `${usrInfo.response.PERFIL}`;
        }

        let profileUpdated = await this._encService.decrypt(`${profUpdEnc}`);
  
        if(profileUpdated == currentProfile){
          try{
            let profile = localStorage.getItem('perfil')!;
            let profInfo: ProfileInterface = await lastValueFrom(this._profilesService.getProfile(
              profile,
              idUser,
              1
            ));
  
            let oldPerm = await this._encService.decrypt(localStorage.getItem('permisos')!);
            let newPerm = JSON.stringify(profInfo.response.PERMISOS);
  
            if(oldPerm != newPerm){
              let permiEnc = await this._encService.encrypt(newPerm);
              localStorage.setItem('permisos', permiEnc);
              this.menuItems = [];

              this.nestedMenu.forEach(item => {
                let idMod = item.IDMODULO;
                let modPerm = profInfo.response.PERMISOS.permissions.filter(item2 => item2.id == idMod)[0];
                let access = modPerm.access;
                if(access > 0){
                  this.menuItems.push(item);
                }
              });

              this.openSnackBar('Sus permisos fueron actualizados.');
            }
          }catch(error: any){
            if(error.error == undefined){
              this.openDialog('Ocurrió un error al actualizar su perfil');
            }else if(error.error.msg == undefined){
              this.openDialog('Ocurrió un error al actualizar su perfil');
            }else{
              this.openDialog(error.error.msg);
            }
          }
        }
      });
  
      this._socketService.advicePublished().subscribe(async (adviceID) => {
        let idEnc = localStorage.getItem('idusuario')!;
  
        let advice: AdviceResponse = await lastValueFrom(this._advicesService.getAdvice(`${adviceID}`, idEnc, 1));
        let userPublish = await this._encService.decrypt(advice.response.IDUSUARIO);
        let idDec = await this._encService.decrypt(idEnc!);
  
        if(userPublish != idDec){
          let audStr = await this._encService.decrypt(advice.response.AUDIENCIA);
          let audArr = JSON.parse(audStr);
  
          let profiles: string[] = [];
          let users: string[] = [];
  
          audArr.forEach((item: any) => {
            let itemArr = item.split('-');
  
            if(itemArr[0] == 'prof'){
              profiles.push(itemArr[1]);
            }else{
              users.push(itemArr[1]);
            }
          });
  
          let perfEnc = localStorage.getItem('perfil');
          let perfDec = await this._encService.decrypt(perfEnc!);
  
          if(profiles.includes(perfDec) || users.includes(idDec)){
            this.openAdviceAlert(advice.response);
          }
        }
      })
  
      this._socketService.closeSessions().subscribe((data) => {
        this._dialg.open(BasicAlertComponent, {
          data: {
            title: 'Modo mantenimiento activado',
            body: 'El modo mantenimiento fue activado por un administrador, el sistema entrará en este modo en 5 minutos, por lo tanto deberá guardar sus cambios y cerrar sesión antes de terminar el tiempo.'
          }
        });
  
        this.maintenanceActivated = true;
  
        let interval = setInterval(() => {
          if(this.secondsLeft == 0 && this.minutesLeft > 0){
            this.minutesLeft--;
            this.secondsLeft = 59;
          }else if(this.secondsLeft > 0 && this.minutesLeft >= 0){
            this.secondsLeft--;
          }else{
            clearInterval(interval);
            this.logout();
          }
  
          let secondsStr = this.secondsLeft > 9 ? `${this.secondsLeft}` : `0${this.secondsLeft}`;
          this.timeLeft = `${this.minutesLeft}:${secondsStr}`;
        }, 1000);
      });

      let userName = localStorage.getItem('nombre_usuario');
      let name = await this._encService.decrypt(userName!);
      
      this.userName = name;
      this.nestedMenu = menu.response;
      
      this.isLoading = false;
      this.checkCatalogues();
    }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.errorsCont++;
      this.openDialog(msg);
    }
  }

  openSnackBar(msg: string){
    this._snackBar.open(msg, undefined, {
      duration: 2500,
    });
  }

  openDialog(msg: string){
    let msgFin = this.errorsCont < 3 ? msg : 'El error persiste, por favor contacte al departamenteo de TI para solucionarlo.';
    let _dialogRef = this._dialg.open(AlertComponent, {
      width: '300px',
      data: {
        icon: "error",
        title: '¡Error!',
        description: msgFin
      }
    });

    _dialogRef.afterClosed().subscribe((_) => {
      if(this.errorsCont < 3){
        location.reload();
      }else{
        this.logout();
      }
    })
  }

  openAdviceAlert(advice: Advice){
    this._dialg.open(AdviceAlertComponent, {
      data: advice
    });
  }

  openViewProfilesAdmin() {
    this._router.navigate([
      'sam/users-profiles'
    ]);
  }

  openViewUsersAdmin() {
    this._router.navigate([
      'sam/new-user'
    ]);
  }

  logout () {
    this._loginDataService.logout()
  }

  async getModules(){
    try{
      let permEnc = localStorage.getItem('permisos');
      let permDec = await this._encService.decrypt(permEnc!);
      let permissions: Permissions = JSON.parse(permDec);

      let idEnc = localStorage.getItem('idusuario')!;
      let menu: NestedMenuInterface = await lastValueFrom(this._modulesService.getMenu(idEnc, 1));

      this.menuItems = menu.response;
    }catch(error: any){
      let errorStr = "";

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

      this.openDialog(errorStr);
    }
  }

  async navigate(modID: string){
    let route = modID.substring(10, modID.length);
    this.modulesActivated = false;
    this._router.navigate([`sam/${route}`]);
  }

  public onResize(){
    this.title = window.innerWidth <= 1050 ? 'SAM L1' : 'Sistema de Ayuda al Manteniemiento L1';
  }

  closeNestedMenu(){
    this.modulesActivated = false;
  }

  openMyProfile(){
    this._dialg.open(MyProfileComponent, {
      width: '580px'
    });
  }

  private async checkCatalogues() {
    const encPermisos:string = localStorage.getItem('permisos')!;
    const strPermisos:string = await this._encService.decrypt(encPermisos);
    const arrPermisos = JSON.parse(strPermisos);

    await Promise.all(
      arrPermisos.permissions.map(async (modules:any) => {      
        if (modules.id === 'S002V01M05GEAD' && modules.access > 0) {

          await Promise.all(
            modules.children.map(async (submodule:any) => {
              if (submodule.id === 'S002V02S02PROV' && submodule.access > 0) {

                await Promise.all(
                  submodule.children.map(async (functions:any) => {
                    if (functions.id === 'S002V01F05GVPA' && functions.access == 2) {
                      let catalogCoins = localStorage.getItem('catalogo_moneda');                
                      if (catalogCoins === null) {
                        const idUser:string = this.resourcesService.getUser();
                        const line: number = parseInt(this.resourcesService.getLineNumber());
                        await lastValueFrom(this._cataloguesService.getGeneralCatalogueInfo('c_Moneda', 5, idUser, line)).then(
                          async (responseData:ResponseDataCatalogueCoins) => {
                            if (!responseData.error) {    
                              let arrCataloguesCoinsDocument:Array<CatalogueCoinsDocument> = responseData.response;
                              let arrCataloguesCoins:Array<CatalogueCoins> = arrCataloguesCoinsDocument.map((cataloguesCoins:CatalogueCoinsDocument) =>  {
                                return {
                                  C_MONEDA: cataloguesCoins.c_Moneda,
                                  DESCRIPCION: cataloguesCoins.Descripción,
                                  DECIMALES: cataloguesCoins.Decimales,
                                  PORCENTAJE_VARIACION: cataloguesCoins.Porcentaje_variación,
                                  FECHA_INICIO_DE_VIGENCIA: cataloguesCoins.Fecha_inicio_de_vigencia,
                                  FECHA_FIN_DE_VIGENCIA: cataloguesCoins.Fecha_fin_de_vigencia,
                                }
                              });
                              arrCataloguesCoins = arrCataloguesCoins.filter((cataloguesCoins:CatalogueCoins) =>  
                                cataloguesCoins.C_MONEDA !== null && cataloguesCoins.DESCRIPCION !== null
                              );
      
                              const strCataloguesCoins:string = JSON.stringify(arrCataloguesCoins);
                              const encCataloguesCoins:string = await this._encService.encrypt(strCataloguesCoins);
                              localStorage.setItem('catalogo_moneda', encCataloguesCoins);
                            } else {
                              this.resourcesService.openSnackBar(`${responseData.msg}`);
                            }
                          }, (httpErrorResponse:HttpErrorResponse) => this.resourcesService.checkErrors(httpErrorResponse)
                        );
                      } 
      
                      let catalogMethodPay = localStorage.getItem('catalogo_metodo_pago');
                      if (catalogMethodPay === null) {
                        const idUser:string = this.resourcesService.getUser();
                        const line: number = parseInt(this.resourcesService.getLineNumber());
                        await lastValueFrom(this._cataloguesService.getGeneralCatalogueInfo('c_FormaPago', 6, idUser, line)).then(
                          async (responseData:ResponseDataCataloguePaymentMethod) => {
                            if (!responseData.error) {                        
                              let arrCataloguesPaymentMethodDocument:Array<CataloguePaymentMethodDocument> = responseData.response;
                              let arrCataloguesPaymentMethod: Array<CataloguePaymentMethod> = arrCataloguesPaymentMethodDocument.map(( cataloguePaymentMethod:CataloguePaymentMethodDocument ) => {
                                return {
                                  C_FORMAPAGO: cataloguePaymentMethod.c_FormaPago,
                                  DESCRIPCION: cataloguePaymentMethod.Descripción,
                                  BANCARIZADO: cataloguePaymentMethod.Bancarizado,
                                  NUMERO_DE_OPERACION: cataloguePaymentMethod.Número_de_operación,
                                  RFC_DEL_EMISOR_DE_LA_CUENTA_ORDENANTE: cataloguePaymentMethod.RFC_del_Emisor_de_la_cuenta_ordenante,
                                  CUENTA_ORDENANTE: cataloguePaymentMethod.Cuenta_Ordenante,
                                  PATRON_PARA_CUENTA_ORDENANTE: cataloguePaymentMethod.Patrón_para_cuenta_ordenante,
                                  RFC_DEL_EMISOR_CUENTA_DE_BENEFICIARIO: cataloguePaymentMethod.RFC_del_Emisor_Cuenta_de_Beneficiario,
                                  CUENTA_DE_BENENFICIARIO: cataloguePaymentMethod.Cuenta_de_Benenficiario,
                                  PATRON_PARA_CUENTA_BENEFICIARIA: cataloguePaymentMethod.Patrón_para_cuenta_Beneficiaria,
                                  TIPO_CADENA_PAGO: cataloguePaymentMethod.Tipo_Cadena_Pago,
                                  NOMBRE_DEL_BANCO_EMISOR_DE_LA_CUENTA_ORDENANTE_EN_CASO_DE_EXTRANJERO: cataloguePaymentMethod.Nombre_del_Banco_emisor_de_la_cuenta_ordenante_en_caso_de_extranjero,
                                  FECHA_INICIO_DE_VIGENCIA: cataloguePaymentMethod.Fecha_inicio_de_vigencia,
                                  FECHA_FIN_DE_VIGENCIA: cataloguePaymentMethod.Fecha_fin_de_vigencia,
                                }
                              });
                              arrCataloguesPaymentMethod = arrCataloguesPaymentMethod.filter((cataloguesMethodPay:CataloguePaymentMethod) => 
                                cataloguesMethodPay.C_FORMAPAGO !== null && cataloguesMethodPay.DESCRIPCION !== null 
                              );
                              localStorage.removeItem
                              const strCataloguesPaymentMethod:string = JSON.stringify(arrCataloguesPaymentMethod);
                              const encCataloguesPaymentMethod:string = await this._encService.encrypt(strCataloguesPaymentMethod);
                              localStorage.setItem('catalogo_metodo_pago', encCataloguesPaymentMethod);
                            } else {
                              this.resourcesService.openSnackBar(`${responseData.msg}`);
                            }
                          }, (httpErrorResponse:HttpErrorResponse) => this.resourcesService.checkErrors(httpErrorResponse)
                        );
                      }  
                    }
                  })
                );

              } 
            })
          );
        } 
      })
    );
  }
}
