import {
  Component,
  ViewChild,
  OnInit,
  ElementRef,
  Inject,
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router';
import { AlertComponent } from 'src/app/components/resources/dialogs/alert/alert.component';
import { EncService } from 'src/app/services/enc/enc.service';
import { ResourcesService } from 'src/app/services/resources/resources.service';
import { lastValueFrom } from 'rxjs';

import { WebviewerComponent } from './webviewer/webviewer.component';
import { MatSnackBar } from '@angular/material/snack-bar';
import { GdelService } from 'src/app/services/document-management/gdel.service';
import { docClassification, modules, supportedFiles } from 'src/environments/environment.prod';
import { DateRangePickerComponent } from './date-range-picker/date-range-picker.component';
import { FormControl } from '@angular/forms';
import { FindedFile, FindedFilesResponse } from 'src/app/interfaces/finded-files.interface';
import { UploadDialogComponent } from './upload-dialog/upload-dialog.component';
import { DOCUMENT } from '@angular/common';
import { ShareFileComponent } from './share-file/share-file.component';
import { AccessDialogComponent } from './access-dialog/access-dialog.component';
import { OrderAssociatonComponent } from './order-associaton/order-associaton.component';

export interface FoundedFiles{
  CODIGO: string;
  VERSION: string;
  NOMBRE: string;
  TAMANIO: string;
  USRREG: string;
  ACCESO: UsersAccess[];
}
export interface UsersAccess{
  userLabel: string;
  userName: string;
  userColor: string;
  isTrigger: boolean;
}
@Component({
  selector: 'app-gdel',
  templateUrl: './gdel.component.html',
  styleUrls: ['./gdel.component.css'],
})
export class GDELComponent implements OnInit {
  public btnSmall: boolean;

  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  category: string;

  modulesArr = modules;
  clasificationsArr = docClassification;
  supportedFilesArr = supportedFiles;

  startDate: Date | null;
  endDate: Date | null;

  @ViewChild('dateRange') dateRange?: ElementRef;
  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  moduleControl: FormControl;
  clasificationControl: FormControl;
  fileNameControl: FormControl;
  fileTypeControl: FormControl;
  datesRangeControl: FormControl;

  files: FindedFile[];
  dataSource: MatTableDataSource<FoundedFiles>;
  displayedColumns = ['CODIGO', 'VERSION', 'NOMBRE', 'TAMANIO', 'USRREG', 'ACCESO', 'ACCIONES'];

  avatarColors = {
    A: 244, B: 67, C:  54, D: 233, E: 30, F:  99, G: 156, H:  39, I: 176, 
    J: 103, K: 58, L:  58, M: 183, N: 63, Ñ:  81, O: 181, P:  33, Q: 150, 
    R: 243, S:  3, T: 169, U: 244, V: 76, W: 175, X:  80, Y: 255, Z: 193
  };

  constructor(
    @Inject(DOCUMENT) private _document: Document,
    private _encService: EncService,
    private _dialog: MatDialog,
    private _gdelService: GdelService,
    private _snackBar: MatSnackBar,
  ) {
    this.btnSmall = false;
    this.isLoading = true;
    this.hasError = true;
    this.errorStr = '';
    this.category = 'my-files';
    this.startDate = null;
    this.endDate = null;

    this.moduleControl = new FormControl('');
    this.clasificationControl = new FormControl('');
    this.fileNameControl = new FormControl('');
    this.fileTypeControl = new FormControl('');
    this.datesRangeControl = new FormControl('');

    this.dataSource = new MatTableDataSource();
    this.files = [];
  }

  ngOnInit(): void {
    this.moduleControl.valueChanges.subscribe(mod => {
      let cla = this.clasificationControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let dna = this.fileNameControl.value;
      let ext = this.fileTypeControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    });

    this.clasificationControl.valueChanges.subscribe(cla => {
      let mod = this.moduleControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let dna = this.fileNameControl.value;
      let ext = this.fileTypeControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    });

    this.fileNameControl.valueChanges.subscribe(dna => {
      let mod = this.moduleControl.value;
      let cla = this.clasificationControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let ext = this.fileTypeControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    });

    this.fileTypeControl.valueChanges.subscribe(ext => {
      let mod = this.moduleControl.value;
      let cla = this.clasificationControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let dna = this.fileNameControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    });

    this.getFiles(
      this.moduleControl.value,
      this.clasificationControl.value,
      this.startDate,
      this.endDate,
      this.fileNameControl.value,
      this.fileTypeControl.value
    );
    /*this.onResize();

         this.dataSource.data = [
      {
        ID: '01-ADSI-CA-230120-000001=01',
        NAME: 'Test',
        EXT: '.doc',
        SIZE: '20MB',
        VERSION: '1',
        FRMOD: '22/02/13',
        USMOD: 'CAVA07',
      },
      {
        ID: '01-ADSI-CA-230100-000002=02',
        NAME: 'Test2',
        EXT: '.pdf',
        SIZE: '10MB',
        VERSION: '2',
        FRMOD: '22/02/12',
        USMOD: 'CAVA07',
      },
    ]; 
    this.getDocuments();*/
  }

  public onResize(): void {
    this.btnSmall = window.innerWidth <= 1573;
  }

  updateCategory(category: string){
    let mod = this.moduleControl.value;
    let cla = this.clasificationControl.value;
    let sda = this.startDate;
    let eda = this.endDate;
    let dna = this.fileNameControl.value;
    let ext = this.fileTypeControl.value;

    this.category = category;
    this.getFiles(mod, cla, sda, eda, dna, ext);
  }

  openDateRangePicker(){
    let dialogRef = this._dialog.open(DateRangePickerComponent, {
      disableClose: true,
      width: '480px',
      data: {
        startDate: this.startDate,
        endDate: this.endDate
      }
    });

    dialogRef.afterClosed().subscribe(res => {
      if(res != null && res != undefined && res != ''){
        let resObj = JSON.parse(res);
        let dateRange = "";

        if(resObj.startDate != null || resObj.endDate != null){
          if(resObj.startDate != null){
            let startDateTimeArr = resObj.startDate.split('T');
            let startDateArr = startDateTimeArr[0].split('-').reverse();
            let startDateStr = startDateArr.join('/');
  
            this.startDate = new Date(resObj.startDate);
            dateRange += `desde ${startDateStr}, `;
          }
          
          if(resObj.endDate != null){
            let endDateTimeArr = resObj.endDate.split('T');
            let endDateArr = endDateTimeArr[0].split('-').reverse();
            let endDateStr = endDateArr.join('/');
  
            this.endDate = new Date(resObj.endDate);
            dateRange += `hasta ${endDateStr}, `;
          }
  
          let fl = dateRange[0].toUpperCase();
          let dateRangeArr = dateRange.split("");
  
          dateRangeArr[0] = fl;
          dateRange = dateRangeArr.join("");
          dateRange = dateRange.substring(0, dateRange.length - 2);

          this.dateRange!.nativeElement.value = dateRange;
          this.getFiles(
            this.moduleControl.value,
            this.clasificationControl.value,
            this.startDate,
            this.endDate,
            this.fileNameControl.value,
            this.fileTypeControl.value,
          );
        }
      }
    });
  }

  async getFiles(module: string | undefined, clas: string | undefined, startDate: Date | null, endDate: Date | null, name: string | undefined, type: string | undefined){
    try{
      this.isLoading = true;
      this.hasError = false;
      this.errorStr = "";

      let mod = module == undefined || module == '' ? '-' : module;
      let cla = clas == undefined || clas == '' ? '-' : clas;
      let sda = startDate == null ? '-' : this.formatSearchDate(startDate);
      let eda = endDate == null ? '-' : this.formatSearchDate(endDate);
      let dna = name == undefined || name == '' ? '-' : name;
      let ext = type == undefined || type == '' ? '-' : JSON.stringify(type.split(','));
      let idUser = localStorage.getItem('idusuario')!;

      let files: FindedFilesResponse = await lastValueFrom(this._gdelService.getFiles(
        mod, cla, sda, eda, dna, ext, this.category, idUser, 1
      ));

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

      if(!this.hasError){
        this.files = files.response;
        let filesFound: FoundedFiles[] = [];
        files.response.forEach(file => {
          let fileSize = this.formatBytes(file.TAMANIO);
          let fileAccess = this.getUsersAccess(file.ACCESO);
          let fileObj: FoundedFiles = {
            CODIGO: file.CODIGO,
            VERSION: file.VERSION,
            NOMBRE: file.NOMBRE,
            TAMANIO: fileSize,
            USRREG: file.USRREG,
            ACCESO: fileAccess,
          };

          filesFound.push(fileObj);
        });
        
        this.dataSource = new MatTableDataSource(filesFound);
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;
      }

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

  formatSearchDate(date: Date): string{
    let day = date.getDate() < 10 ? `0${date.getDate()}` : `${date.getDate()}`;
    let month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : `${date.getMonth() + 1}`;
    let fullYear = `${date.getFullYear()}`;
    let year = fullYear.substring(2);
    
    return `${year}${month}${day}`;
  }

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

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

  getUsersAccess(accessStr: string): UsersAccess[]{
    let accessArr = JSON.parse(accessStr);
    let arrFn: UsersAccess[] = [];

    for(const user of accessArr){
      let userNameArr = user.split(' ');
      let userLabel = '';

      for(let i = 0; i < 2; i++){
        userLabel += userNameArr[i][0];
      }

      let userColor = "rgb(";
      for(let i = 0; i < 3; i++){
        let char: never = user.charAt(i) as never;
        let code = this.avatarColors[char];

        userColor += `${code}, `;
      }

      userColor = userColor.substring(0, userColor.length - 2);
      userColor += ")";

      let userObj: UsersAccess = {
        userLabel: userLabel,
        userName: user,
        userColor: userColor,
        isTrigger: false,
      }

      arrFn.push(userObj);
    }

    let arrFnAux: UsersAccess[] = [];
    if(arrFn.length > 4){
      for(let i = 0; i < 3; i++){
        arrFnAux.push(arrFn[i]);
      }

      let moreUsers: UsersAccess = {
        userLabel: `${arrFn.length - 3}+`,
        userName: `Ver ${arrFn.length - 3} más...`,
        userColor: 'rgba(0,0,0,0.54)',
        isTrigger: true,
      };

      arrFnAux.push(moreUsers);
      return arrFnAux;
    }

    return arrFn;
  }

  clearDatesRange(){
    this.startDate = null;
    this.endDate = null;
    this.datesRangeControl.setValue('');

    this.getFiles(
      this.moduleControl.value,
      this.clasificationControl.value,
      this.startDate,
      this.endDate,
      this.fileNameControl.value,
      this.fileTypeControl.value
    );
  }

  openUploadDialog(){
    let dialogRef = this._dialog.open(UploadDialogComponent, {
      width: '480px',
      disableClose: true,
    });

    dialogRef.afterClosed().subscribe(res => {
      if(res == true){
        let mod = this.moduleControl.value;
        let cla = this.clasificationControl.value;
        let sda = this.startDate;
        let eda = this.endDate;
        let dna = this.fileNameControl.value;
        let ext = this.fileTypeControl.value;

        this.getFiles(mod, cla, sda, eda, dna, ext);
      }
    });
  }

  async downloadFile(code: string, version: string, name: string){
    try{
      let idFile = `${code}=${version}=${name}`;
      this.openSnackBar(`Iniciando la descarga del archivo ${idFile}...`);

      let idFileEnc = await this._encService.encrypt(idFile);
      let download = this._document.getElementById(`download`) as HTMLAnchorElement;
  
      let idUser = localStorage.getItem('idusuario')!;
      let downloadToken = await lastValueFrom(this._gdelService.getDownloadToken(
        idFileEnc,
        idUser,
        1
      ));
  
      download.href = `http://git.ittec.mx/sam/public/api/download-file/${downloadToken.response.TOKEN}/${idUser}/1`;
      download.download = idFile;
      download.click();
    }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 openViewer(code: string, version: string, name: string) {
    try{
      let idFile = `${code}=${version}=${name}`;
      this.openSnackBar(`Abriendo el archivo ${idFile}...`);
      
      let idFileEnc = await this._encService.encrypt(idFile);
      let idUser = localStorage.getItem('idusuario')!;

      let publicURL = await lastValueFrom(this._gdelService.getPublicDocumentUrl(
        idFileEnc,
        idUser,
        1
      ));

      let fileData = {
        url: publicURL.response.public_uri,
      };

      this._dialog.open(WebviewerComponent, {
        data: fileData,
        width: '100%',
      });
    }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);
      }
    }
  }

  openShareDialog(code: string, version: string, name: string){
    let idFile = `${code}=${version}=${name}`;
    let dialogRef = this._dialog.open(ShareFileComponent, {
      width: '720px',
      disableClose: true,
      data: {
        idFile: idFile,
      }
    })

    dialogRef.afterClosed().subscribe((res) => {
      this.updateFilePermissions(idFile, res);
    })
  }

  async updateFilePermissions(idFile: string, permissions: string){
    try{
      this.openSnackBar(`Actualizando permisos del archivo ${idFile}`);
      this.isLoading = true;
      this.hasError = false;
      this.errorStr = '';

      let idFileEnc = await this._encService.encrypt(idFile);
      let idUser = localStorage.getItem('idusuario');
      let formData = new FormData();

      formData.append('id_user', idUser!);
      formData.append('id_file', idFileEnc);
      formData.append('linea', '1');
      formData.append('permissions', permissions);

      await lastValueFrom(this._gdelService.updateFilePermissions(formData));
      this.openSnackBar(`Los permisos se actualizaron correctamente`);
      
      let mod = this.moduleControl.value;
      let cla = this.clasificationControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let dna = this.fileNameControl.value;
      let ext = this.fileTypeControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    }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;
    }
  }

  openAccessDialog(code: string, version: string, name: string, isTrigger: boolean, isDeleted: boolean){
    if(isTrigger){
      let file = this.files.filter(item => item.CODIGO == code && item.VERSION == version && item.NOMBRE == name)[0];
      let accessStr = file.ACCESO;
      let idFile = `${code}=${version}=${name}`;

      let dialogRef = this._dialog.open(AccessDialogComponent, {
        width: '720px',
        data: {
          idFile: idFile,
          accessStr: accessStr,
          isDeleted: isDeleted
        }
      });

      dialogRef.afterClosed().subscribe(res => {
        if(res == true){
          this.openShareDialog(code, version, name);
        }
      })
    }
  }

  confirmDelete(code: string, version: string, name: string){
    let idFile = `${code}=${version}=${name}`;
    let dialogRef = this._dialog.open(AlertComponent, {
      disableClose: true,
      width: '480px',
      data: {
        title: 'Confirmar acción',
        icon: 'warning',
        description: `¿Está seguro de querer eliminar el archivo ${idFile}?`,
        description2: 'Esta acción no se puede deshacer'
      }
    });

    dialogRef.afterClosed().subscribe(res => {
      if(res == true){
        this.deleteFile(idFile);
      }
    });
  }

  async deleteFile(idFile: string){
    try{
      let idUser = localStorage.getItem('idusuario');
      let idFileEnc = await this._encService.encrypt(idFile);
      let formData = new FormData();

      formData.append('id_user', idUser!);
      formData.append('id_file', idFileEnc);
      formData.append('linea', '1');

      await lastValueFrom(this._gdelService.deleteFile(formData));
      this.openSnackBar('El archivo se eliminó correctamente.');
      
      let mod = this.moduleControl.value;
      let cla = this.clasificationControl.value;
      let sda = this.startDate;
      let eda = this.endDate;
      let dna = this.fileNameControl.value;
      let ext = this.fileTypeControl.value;

      this.getFiles(mod, cla, sda, eda, dna, ext);
    }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);
      }
    }
  }

  openAssociationDialog(code: string, version: string, name: string){
    let idFile = `${code}=${version}=${name}`;
    this._dialog.open(OrderAssociatonComponent, {
      width: '840px',
      disableClose: true,
      data: {
        idFile: idFile,
      }
    });
  }
}
