import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import { FindedFile, FindedFilesResponse } from '../../../interfaces/finded-files.interface';
import { MatTableDataSource } from '@angular/material/table';
import { FoundedFiles, UsersAccess } from '../gdel.component';
import { docClassification, modules, supportedFiles } from '../../../../environments/environment.prod';
import { FormControl } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { DOCUMENT } from '@angular/common';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { EncService } from '../../../services/enc.service';
import { GdelService } from '../../../services/gdel.service';
import { AdvicesService } from '../../../services/advices.service';
import { ResourcesService } from '../../../services/resources.service';
import { TempFileInfo } from '../../../interfaces/temp-file-info.interface';
import { lastValueFrom } from 'rxjs';
import { DateRangePickerComponent } from '../date-range-picker/date-range-picker.component';
import { AttachedListComponent } from './attached-list/attached-list.component';

@Component({
    selector: 'app-search-file-dialog',
    templateUrl: './search-file-dialog.component.html',
    styleUrl: './search-file-dialog.component.css',
    standalone: false
})
export class SearchFileDialogComponent implements OnInit {
  files: FindedFile[];
  dataSource?: MatTableDataSource<FoundedFiles>;
  displayedColumns = ['CODIGO', 'VERSION', 'NOMBRE', 'TAMANIO', 'ACCIONES'];
  
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  category: string;

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

  attachedFiles: FindedFile[];

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

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

  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
  };
  
  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;
  @ViewChild('dateRange') dateRange?: ElementRef;

  constructor(
    @Inject(DOCUMENT) private _document: Document,
    @Inject(MAT_DIALOG_DATA) private _data: any,
    private _encService: EncService,
    private _gdelService: GdelService,
    private _dialogReference: MatDialogRef<SearchFileDialogComponent>,
    private _advicesServices: AdvicesService,
    private _dialog: MatDialog,
    private _resourcesService: ResourcesService,
  ) { 
    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.attachedFiles = [];
    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.init();
  }

  async init(){
    let files: TempFileInfo[] = this._data.files;
    for(const file of files){
      let idDec = await this._encService.decrypt(file.id);
      let idArr = idDec.split('=');
      let fileObj: FindedFile = {
        CODIGO: idArr[0],
        VERSION: idArr[1],
        NOMBRE: idArr[2],
        TAMANIO: file.size,
        USRREG: '',
        ACCESO: ''
      };

      this.attachedFiles.push(fileObj);
    }

    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 as number);
          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}`;
  }

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

  openDateRangePicker(){
    let dialogRef = this._dialog.open(DateRangePickerComponent, {
      disableClose: true,
      width: '480px',
      maxWidth: '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,
          );
        }
      }
    });
  }

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

  attachFile(file: FindedFile){
    let search = this.attachedFiles.filter(item => item.CODIGO == file.CODIGO && item.VERSION == file.VERSION);
    if(search.length > 0){
      let attachedAux: FindedFile[] = [];
      this.attachedFiles.forEach(item => {
        if(item.CODIGO != file.CODIGO && item.VERSION != file.VERSION){
          attachedAux.push(item);
        }
      });

      this.attachedFiles = attachedAux;
    }else{
      this.attachedFiles.push(file);
    }
  }

  isAttached(file: FindedFile){
    let search = this.attachedFiles.filter(item => item.CODIGO == file.CODIGO && item.VERSION == file.VERSION);
    return search.length > 0;
  }

  async openViewer(file: FindedFile){
    this._resourcesService.openSnackBar('En desarrollo');
  }

  async downloadFile(file: FindedFile){
    try{
      /*let idUser = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));

      let fileName = `${file.CODIGO}=${file.VERSION}=${file.NOMBRE}`;
      let fileEnc = await this._encService.encrypt(fileName);
      let fileShort = await lastValueFrom(this._encService.shortEncrypt(fileEnc));

      let downloadToken = await lastValueFrom(this._advicesServices.getDownloadToken(
        fileShort.response.encrypted,
        shortEnc.response.encrypted,
        1
      ));

      let download = this._document.getElementById(`download-${file.CODIGO}`) as HTMLAnchorElement;
      download.href = `http://git.ittec.mx/sam/public/api/download-file/${downloadToken.response.TOKEN}/${shortEnc.response.encrypted}/1`;
      download.download = fileName;
      download.click();*/
    }catch(error: any){
      if(error.error == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado');
      }else if(error.error.msg == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado');
      }else{
        this._resourcesService.openSnackBar(error.error.msg);
      }
    }
  }

  openAttachedList(){
    let dialogRef = this._dialog.open(AttachedListComponent, {
      width: '384px',
      maxWidth: '384px',
      data: {
        files: this.attachedFiles
      }
    });

    dialogRef.afterClosed().subscribe(res => {
      if(res != null && res != undefined && res != ''){
        let resArr: FindedFile[] = JSON.parse(res);
        this.attachedFiles = resArr;
      }
    });
  }

  saveFiles(){
    let attachedStr = JSON.stringify(this.attachedFiles);
    this._dialogReference.close(attachedStr);
  }
}
