import { FunctionsService } from './../../../services/functions.service';
import { MenuFunction, MenuResponse } from './../../../interfaces/menu.interface';
import { Submodules, SubmodulesResponse } from './../../../interfaces/submodules.interface';
import { LoginParamsResponse } from './../../../interfaces/login-params.interface';
import { AlertComponent } from 'src/app/components/resources/dialogs/alert/alert.component';
import { MatDialog } from '@angular/material/dialog';
import { availableFiles } from './../../../../environments/environment.prod';
import { ModuleInterface } from './../../../interfaces/modules.interface';
import { ModulesService } from './../../../services/modules.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MaterialIcon, MaterialIconsResponse } from './../../../interfaces/material-icons.interface';
import { SystemAdminService } from 'src/app/services/system-admin.service';
import { lastValueFrom } from 'rxjs';
import { EncService } from 'src/app/services/enc/enc.service';
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { TempFileInfo } from '../advices/new-advice/new-advice.component';
import { MatTableDataSource } from '@angular/material/table';
import { GETBFOService } from 'src/app/services/forms-management/getbfo/getbfo.service';
import { HttpErrorResponse } from '@angular/common/http';
import { ResourcesService } from 'src/app/services/resources/resources.service';
import { AlertData } from 'src/app/interfaces/alert.interface';
import { Router } from '@angular/router';

@Component({
  selector: 'app-system-params',
  templateUrl: './system-params.component.html',
  styleUrls: ['./system-params.component.css']
})
export class SystemParamsComponent implements OnInit {
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;

  materialIcons: MaterialIcon[];
  modules: ModuleInterface[];
  submodules: Map<string, Submodules[]>;
  functionsPerSubmodule: Map<string, Map<string, MenuFunction[]>>;
  functionsPerModule: Map<string, MenuFunction[]>;
  iconsArr: Map<string, string[]>;
  iconsCategories: string[];

  moduleName = new FormControl('');
  moduleIcon = new FormControl('');
  submoduleModule = new FormControl('');
  submoduleName = new FormControl('');
  submoduleIcon = new FormControl('');
  functionModule = new FormControl('');
  functionSubmodule = new FormControl('');
  functionName = new FormControl('');
  functionIcon = new FormControl('');

  imageFormats = ["jpg", "png", "gif", "bmp", "tiff", "svg"];
  attached: TempFileInfo[];

  upImg: boolean;
  upBac: boolean;
  imgStr: string;
  bacStr: string;

  @ViewChild('file') file?: ElementRef;

  public txtBuscador: string;
  public btnSmall: boolean;
  public dataSource: MatTableDataSource<any>;
  public isLoadingForm: boolean = false;
  public displayedColumns: string[];

  constructor(
    public dialog: MatDialog,
    private _encService: EncService,
    private _sysAdminService: SystemAdminService,
    private _snackBar: MatSnackBar,
    private _modulesService: ModulesService,
    private _matDialog: MatDialog,
    private _formService: GETBFOService,
    private _resourcesService: ResourcesService,
    private _router: Router,
    private _funcService: FunctionsService,
  ) {
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = "";

    this.upImg = false;
    this.upBac = false;
    this.imgStr = "";
    this.bacStr = "";
    this.txtBuscador = '';
    this.btnSmall = false;

    this.materialIcons = [];
    this.modules = [];
    this.iconsArr = new Map<string, string[]>;
    this.submodules = new Map<string, Submodules[]>;
    this.functionsPerSubmodule = new Map<string, Map<string, MenuFunction[]>>;
    this.functionsPerModule = new Map<string, MenuFunction[]>;
    this.iconsCategories = [];
    this.attached = [];

    this.dataSource = new MatTableDataSource<any>();
    this.displayedColumns = [ 'NOMBRE_FORM', 'MODULO', 'FECHA_REG', 'ESTADO', 'ACCIONES' ]
  }

  ngOnInit(): void {
    this.getMaterialIcons();
  }

  async getMaterialIcons(){
    try{
      let idUser = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
      let materialIcons: MaterialIconsResponse = await lastValueFrom(this._sysAdminService.getMaterialIcons(shortEnc.response.encrypted, 1));

      this.hasError = materialIcons.error;
      if(!this.hasError){
        this.materialIcons = materialIcons.response;
      }else{
        this.errorStr = materialIcons.msg;
        this.isLoading = false;
      }

      this.materialIcons.forEach(icon => {
        let categorie = icon.categorie[0];
        if(this.iconsArr.has(categorie)){
          let arr = this.iconsArr.get(categorie);
          arr?.push(icon.name);
        }else{
          let arr = [icon.name];
          this.iconsArr.set(categorie, arr);
        }
      });

      this.iconsCategories = Array.from(this.iconsArr.keys());
      this.getModules();
    }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 getModules(){
    try{
      let idUser = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
      //let modules: ModulesInterface = await lastValueFrom(this._modulesService.getModules(shortEnc.response.encrypted, 1));
      let menu: MenuResponse = await lastValueFrom(this._modulesService.getMenu(shortEnc.response.encrypted, 1));

      this.hasError = menu.error;
      if(this.hasError){
        this.errorStr = menu.msg;
        this.isLoading = false;
      }else{
        menu.response.forEach(mod => {
          if(mod.SUBMODULES.length > 0){
            let submodules: Submodules[] = [];
            let submoduleFunctions: Map<string, MenuFunction[]> = new Map<string, MenuFunction[]>;

            mod.SUBMODULES.forEach(submod => {
              if(submod.FUNCIONES.length > 0){
                let functions: MenuFunction[] = [];

                submod.FUNCIONES.forEach(func => {
                  functions.push(func);
                });

                submoduleFunctions.set(submod.IDSUBMODULO, functions);
              }

              let submodule: Submodules = {
                IDSUBMODULO: submod.IDSUBMODULO,
                NOMBRESUBMODULO: submod.NOMBRESUBMODULO,
                ICONOSUBMODULO: submod.ICONOSUBMODULO
              }

              submodules.push(submodule);
            });

            this.functionsPerSubmodule.set(mod.IDMODULO, submoduleFunctions);
            this.submodules.set(mod.IDMODULO, submodules);
          }else{
            let moduleFunctions: MenuFunction[] = [];
            mod.MENUS.forEach(menu => {
              moduleFunctions.push(menu);
            });

            this.functionsPerModule.set(mod.IDMODULO, moduleFunctions);
          }

          let module: ModuleInterface = {
            IDMODULO: mod.IDMODULO,
            NOMBREMODULO: mod.NOMBREMODULO,
            ICONOMODULO: mod.ICONOMODULO,
          };

          this.modules.push(module);
        });

        this.getLoginImages();
      }
    }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 getSubmodules(module: string){
    try{
      let idUser = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));

      let idMod = await this._encService.encriptar(module);
      let modShort = await lastValueFrom(this._encService.shortEncrypt(idMod));
      let submodules: SubmodulesResponse = await lastValueFrom(this._modulesService.getSubmodules(modShort.response.encrypted, shortEnc.response.encrypted, 1));

      this.submodules.set(module, submodules.response);
    }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;
    }
  }

  changeModuleIcon(module: string){
    let mod = this.modules.filter(item => item.IDMODULO == module)[0];
    this.moduleIcon.setValue(mod.ICONOMODULO);
  }

  changeSubmoduleIcon(submodule: string){
    let moduleSelected = this.submodules.get(this.submoduleModule.value!);
    let submoduleSelected = moduleSelected?.filter(item => item.IDSUBMODULO == submodule)[0];
    this.submoduleIcon.setValue(submoduleSelected?.ICONOSUBMODULO!);
  }

  changeFunctionIcon(func: string){
    if(this.functionsPerModule.has(this.functionModule.value!)){
      let moduleSelected = this.functionsPerModule.get(this.functionModule.value!);
      let functionSelected = moduleSelected?.filter(item => item.IDFUNCION == func)[0];
      this.functionIcon.setValue(functionSelected?.ICONOFUNCION!);
    }else{
      let moduleSelected = this.functionsPerSubmodule.get(this.functionModule.value!);
      let submoduleSelected = moduleSelected?.get(this.functionSubmodule.value!);
      let functionSelected = submoduleSelected?.filter(item => item.IDFUNCION == func)[0];
      this.functionIcon.setValue(functionSelected?.ICONOFUNCION!);
    }
  }

  submodChange(){
    this.submoduleName.setValue('');
    this.submoduleIcon.setValue('');
  }

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

  updateModuleIcon(newIcon: string){
    let moduleSelected = this.modules.filter(item => item.IDMODULO == this.moduleName.value)[0];
    let modulesAux: ModuleInterface[] = [];

    this.modules.forEach(module => {
      if(moduleSelected.IDMODULO == module.IDMODULO){
        moduleSelected.ICONOMODULO = newIcon;
        modulesAux.push(moduleSelected);
      }else{
        modulesAux.push(module);
      }
    });

    this.modules = modulesAux;
  }

  updateSubmoduleIcon(newIcon: string){
    let moduleSelected = this.submodules.get(this.submoduleModule.value!);
    let submoduleSelected = moduleSelected?.filter(item => item.IDSUBMODULO == this.submoduleName.value)[0];
    let submodulesAux: Submodules[] = [];

    moduleSelected?.forEach(submodule => {
      if(submoduleSelected?.IDSUBMODULO == submodule.IDSUBMODULO){
        submoduleSelected.ICONOSUBMODULO = newIcon;
        submodulesAux?.push(submoduleSelected);
      }else{
        submodulesAux?.push(submodule);
      }
    });

    this.submodules.set(this.submoduleModule.value!, submodulesAux!);
  }

  updateFunctionIcon(newIcon: string){
    if(this.functionsPerSubmodule.has(this.functionModule.value!)){
      let moduleSelected = this.functionsPerSubmodule.get(this.functionModule.value!);
      let submoduleSelected = moduleSelected?.get(this.functionSubmodule.value!);
      let functionSelected = submoduleSelected?.filter(item => item.IDFUNCION == this.functionName.value)[0];
      let functionsAux: MenuFunction[] = [];

      submoduleSelected?.forEach(func => {
        if(functionSelected?.IDFUNCION == func.IDFUNCION){
          func.ICONOFUNCION = newIcon;
          functionsAux.push(functionSelected);
        }else{
          functionsAux?.push(func);
        }
      });

      moduleSelected?.set(this.functionSubmodule.value!, functionsAux);
      this.functionsPerSubmodule.set(this.functionModule.value!, moduleSelected!);
    }else{
      let moduleSelected = this.functionsPerModule.get(this.functionModule.value!);
      let functionSelected = moduleSelected?.filter(item => item.IDFUNCION == this.functionName.value)[0];
      let moduleAux: MenuFunction[] = [];

      moduleSelected?.forEach(func => {
        if(functionSelected?.IDFUNCION == func.IDFUNCION){
          functionSelected.ICONOFUNCION = newIcon;
          moduleAux?.push(functionSelected);
        }else{
          moduleAux?.push(func);
        }
      });

      this.functionsPerModule.set(this.functionModule.value!, moduleAux);
    }
  }

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

  checkFile(event: any){
    let fileTypes = availableFiles;
    let sizes = Object.keys(fileTypes);
    let extensions = Object.values(fileTypes);

    let extArr = event.target.files[0].name.split(".").reverse();
    let extStr = extArr[0];

    if(this.imageFormats.includes(extStr)){
      let maxFileSize = 1048576 * 250;
      let fileSize = event.target.files[0].size;

      if(fileSize > maxFileSize){
        this.openSnackBar(`El tamaño del archivo supera el límite de 75 MB`);
      }else{
        let dialogRef = this._matDialog.open(AlertComponent, {
          data: {
            title: 'Advertencia',
            icon: 'warning',
            description: '¿Está seguro de realizar la acción solicitada?'
          }
        });

        dialogRef.afterClosed().subscribe(res => {
          if(res == true){
            let type = this.upImg ? 'img' : 'bac';
            this.updateImg(type, event.target.files[0]);
          }else{
            this.upImg = false;
            this.upBac = false;
          }
        });
      }
    }else{
      this.openSnackBar('El archivo seleccionado no tiene un formato de imagen');
    }
  }

  formatBytes(bytes: number, decimals = 2) {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  }

  imageHandler(type: string){
    if(type == 'img'){
      this.upImg = true;
      this.file?.nativeElement.click();
    }else{
      this.upBac = true;
      this.file?.nativeElement.click();
    }
  }

  async updateImg(type: string, fileData: any){
    try{
      let idUser = localStorage.getItem('idusuario');
      let idUserShort = await lastValueFrom(this._encService.shortEncrypt(idUser!));
      let formData = new FormData();

      formData.append('file', fileData);
      formData.append('id_user', idUserShort.response.encrypted);
      formData.append('linea', "1");

      let response = await lastValueFrom(this._sysAdminService.uploadTempFile(formData));
      if(response.error){
        this.openSnackBar(response.msg);
        this.upBac = false;
        this.upImg = false;
      }else{
        let tipo = type == 'img' ? 'image' : 'background';
        let formData = new FormData();

        formData.append('id_user', idUser!);
        formData.append('linea', '1');
        formData.append('tipo', tipo);
        formData.append('archivo', response.response.idArchivo);

        await lastValueFrom(this._sysAdminService.saveLoginImage(formData));

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

      this.upBac = false;
      this.upImg = false;
    }
  }

  async getLoginImages(){
    try{
      let idUser = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
      let loginImages: LoginParamsResponse = await lastValueFrom(this._sysAdminService.getLoginImages(shortEnc.response.encrypted, 1));

      if(loginImages.error){
        this.errorStr = loginImages.msg;
        this.hasError = true;
        this.isLoading = false;
      }else{
        this.imgStr = `http://git.ittec.mx/sam/public/assets/${loginImages.response.login_params.login_image}`;
        this.bacStr = `http://git.ittec.mx/sam/public/assets/${loginImages.response.login_params.login_background}`;

        this.upBac = false;
        this.upImg = false;
        this.obtenerFormularios();
      }
    }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;
    }
  }

  cancelHandle(){
    this.upBac = false;
    this.upImg = false;
  }

  hasSubmodules(idMod: string): boolean{
    let hasSubmodules = this.submodules.has(idMod);
    return !hasSubmodules;
  }

  funcModChange(value: string){
    if(this.submodules.has(value)){
      this.functionSubmodule.enable();
    }else{
      this.functionSubmodule.disable();
    }

    this.functionSubmodule.setValue('');
    this.functionName.setValue('');
    this.functionIcon.setValue('');
  }

  funSubmodChange(){
    this.functionName.setValue('');
    this.functionIcon.setValue('');
  }

  getFunctions(): MenuFunction[]{
    let moduleFunctions = this.functionsPerModule.get(this.functionModule.value!);
    let submoduleFunctions = this.functionsPerSubmodule.get(this.functionModule.value!)?.get(this.functionSubmodule.value!);
    if(moduleFunctions != undefined){
      return moduleFunctions;
    }else if(submoduleFunctions != undefined){
      return submoduleFunctions;
    }else{
      return [];
    }
  }

  async saveModules(){
    try{
      let modulesStr = JSON.stringify(this.modules);
      let modulesEnc = await this._encService.encriptar(modulesStr);
      let modulesShort = await lastValueFrom(this._encService.shortEncrypt(modulesEnc));
      let idUser = localStorage.getItem('idusuario');
      let info = new FormData();

      info.append('id_user', idUser!);
      info.append('linea', '1');
      info.append('module_icons', modulesShort.response.encrypted);

      await lastValueFrom(this._sysAdminService.updateModuleIcons(info));
      this.openSnackBar('Los iconos de los módulos se actualizaron correctamente.');
    }catch(error: any){
      if(error.error == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else if(error.error.msg == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else{
        this.openSnackBar(error.error.msg);
      }
    }
  }

  async saveSubmodules(){
    try{
      let idUser = localStorage.getItem('idusuario');
      let submodulesStr = JSON.stringify(Object.fromEntries(this.submodules));
      let submodulesEnc = await this._encService.encriptar(submodulesStr);
      let submodulesShort = await lastValueFrom(this._encService.shortEncrypt(submodulesEnc));
      let info = new FormData();

      info.append('id_user', idUser!);
      info.append('linea', '1');
      info.append('submodule_icons', submodulesShort.response.encrypted);

      await lastValueFrom(this._sysAdminService.updateSubmoduleIcons(info));
      this.openSnackBar('Los iconos de los submódulos se actualizaron correctamente.');
    }catch(error: any){
      if(error.error == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else if(error.error.msg == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else{
        this.openSnackBar(error.error.msg);
      }
    }
  }

  async saveFunctions(){
    try{
      let functionsPerModuleStr = JSON.stringify(Object.fromEntries(this.functionsPerModule));
      let functionsPerModuleEnc = await this._encService.encriptar(functionsPerModuleStr);
      let functionsPerModuleShort = await lastValueFrom(this._encService.shortEncrypt(functionsPerModuleEnc));

      let functionsPerSubmoduleObjAuxStr = JSON.stringify(Object.fromEntries(this.functionsPerSubmodule));
      let functionsPerSubmoduleObjAux = JSON.parse(functionsPerSubmoduleObjAuxStr);

      this.functionsPerSubmodule.forEach((value, key) => {
        let functionsAux = Object.fromEntries(value);
        functionsPerSubmoduleObjAux[key] = functionsAux;
      });

      let functionsPerSubmoduleStr = JSON.stringify(functionsPerSubmoduleObjAux);
      let functionsPerSubmoduleEnc = await this._encService.encriptar(functionsPerSubmoduleStr);
      let functionsPerSubmoduleShort = await lastValueFrom(this._encService.shortEncrypt(functionsPerSubmoduleEnc));

      let idUser = localStorage.getItem('idusuario');
      let info = new FormData();

      info.append('id_user', idUser!);
      info.append('linea', '1');
      info.append('module_functions_icons', functionsPerModuleShort.response.encrypted);
      info.append('submodule_functions_icons', functionsPerSubmoduleShort.response.encrypted);

      await lastValueFrom(this._sysAdminService.updateFunctionIcons(info));
      this.openSnackBar('Los iconos de las funciones se actualizaron correctamente.');
    }catch(error: any){
      if(error.error == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else if(error.error.msg == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else{
        this.openSnackBar(error.error.msg);
      }
    }
  }

  applyFilter(event: any, type: string){
    let filterValue:string;
    if (type == 'INP') {
      filterValue = (event.target as HTMLInputElement).value;
    }else{
      this.txtBuscador = event;
      filterValue = event;
    }
    this.dataSource!.filter = filterValue.trim().toLowerCase();

    if(this.dataSource?.paginator){
      this.dataSource.paginator.firstPage();
    }
  }

  public async obtenerFormularios() {
    this.isLoading = true;
    await lastValueFrom(this._formService.getForm()).then(
      (data: ResponseData) => {
        this.dataSource.data = !data.error ? data.response : [];
      },(error: HttpErrorResponse) => this._resourcesService.checkErrors(error)
    );
    this.isLoading = false;
  }

  public async alert(type: string, data: any = null) {
    this.isLoadingForm = true;
    let info: AlertData = {} as AlertData;
    switch (type) {
      case 'ELM':
        info = {
          icon: "warning",
          title: "Eliminar Formulario",
          description: "¿Está seguro de eliminar este formulario?"
        };
        break;
    }

    const dialogRef = this.dialog.open(AlertComponent, {
      data: info,
      disableClose: true,
      width: '350px',
    });
    dialogRef.afterClosed().subscribe((result) => {
      if (result) {
        switch (type) {
          case 'ELM':
            this.eliminar(data);
            break;
        }
      }
      this.isLoadingForm = false;
    });
  }

  public async eliminar(codigo_form: string) {
    await lastValueFrom(
      this._formService.deleteForm({ CODIGO_FORM: codigo_form, USER: this._resourcesService.getUser() })
    ).then(
      (data: ResponseData) => {
        if (!data.error) {
          this._resourcesService.openSnackBar('¡Eliminación correcta!');
          this.obtenerFormularios();
        }
      },
      (error: HttpErrorResponse) => this._resourcesService.checkErrors(error)
    );
  }

  public async modificar(codigo_form: number) {
    this.isLoadingForm = true;
    await lastValueFrom(this._formService.getFormData(codigo_form)).then(
      (data: ResponseData) => {
        let str_res = JSON.stringify(data.response);
        this._router.navigate([`sam/getbfo-update/${codigo_form}`]);
      },
      (error: HttpErrorResponse) => this._resourcesService.checkErrors(error)
    );
    this.isLoadingForm = false;
  }

  public formatDate(dateRegister:string, dateUpdate:string | null):string {
    let date:string = (dateUpdate === null) ? dateRegister : dateUpdate;
    return this._funcService.orderDate(date);
  }
}

export interface ResponseData {
  error: boolean;
  msg: string;
  response: Array<any> | any;
}
