import { FinalFileResponse } from './../../../../interfaces/final-file.interface';
import { DocumentManagementService } from './../../../../services/document-management.service';
import { SocketService } from './../../../../services/socket.service';
import { AdvicesService } from './../../../../services/advices.service';
import { FormControl, Validators } from '@angular/forms';
import { MatchErrors } from './../../../users-profiles/profiles-admin/new-profile/new-profile.component';
import { SystemAdminService } from './../../../../services/system-admin.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { availableFiles } from './../../../../../environments/environment.prod';
import { ProfilesResponse } from './../../../../interfaces/profiles.interface';
import { UsersResponse, UserResponse } from './../../../../interfaces/users.interface';
import { lastValueFrom } from 'rxjs';
import { EncService } from 'src/app/services/enc/enc.service';
import { UsersProfilesService } from './../../../../services/users-profiles.service';
import { Component, Input, OnInit, ViewChild, ElementRef } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { AlertComponent } from 'src/app/components/resources/dialogs/alert/alert.component';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute } from '@angular/router';
import { AdviceResponse } from 'src/app/interfaces/advice.interface';

interface Division{
  value: string;
  viewValue: string;
}

interface DivisionGroup{
  name: string;
  division: Division[];
}

export interface TempFileInfo{
  id: string,
  name: string,
  size: string
}

interface Hour{
  value: string;
  label: string;
}

@Component({
  selector: 'app-new-advice',
  templateUrl: './new-advice.component.html',
  styleUrls: ['./new-advice.component.css']
})
export class NewAdviceComponent implements OnInit {
  isLoading: boolean;
  isUploading: boolean;
  isNew: boolean;
  hasError: boolean;
  errorStr: string;
  downloadLink: string;
  idAdvice: string;
  users: UserResponse[];
  divisions: DivisionGroup[];
  attached: TempFileInfo[];
  hours: Hour[];

  dataSource?: MatTableDataSource<TempFileInfo>;
  displayedColumns: string[] =  ['ID', 'NOMBRE', 'PESO', 'ACCIONES'];

  @ViewChild(MatPaginator) paginator?: MatPaginator;
  @ViewChild(MatSort) sort?: MatSort;
  @ViewChild("download") a?: ElementRef;

  errorMatcher = new MatchErrors();
  adviceTitle = new FormControl('', [Validators.required, Validators.minLength(8), Validators.maxLength(100)]);
  adviceDate = new FormControl('', Validators.required);
  adviceHour = new FormControl('', Validators.required);
  adviceContent = new FormControl('', Validators.required);
  adviceAudience = new FormControl('', Validators.required);

  public btnSmall: boolean = false;
  public txtBuscador:string;

  constructor(
    private _usersProfilesService: UsersProfilesService,
    private _systemAdminService: SystemAdminService,
    private _encService: EncService,
    private _snackBar: MatSnackBar,
    private _dialg: MatDialog,
    private _advicesService: AdvicesService,
    private _socketService: SocketService,
    private _route: ActivatedRoute, 
    private _documentManagement: DocumentManagementService,
  ) { 
    this.isLoading = true;
    this.isUploading = false;
    this.hasError = false;
    this.isNew = false;
    this.errorStr = "";
    this.downloadLink = "";
    this.idAdvice = "";
    this.users = [];
    this.divisions = [];
    this.attached = [];
    this.hours = [];
    this.txtBuscador = '';
  }

  ngOnInit(): void {
    for(let i = 0; i <= 23; i++){
      let timeLapse = i < 12 ? 'AM' : 'PM';
      let hour = i > 12 ? i - 12 : i;
      let hourStr = hour < 10 ? `0${hour}` : `${hour}`;

      let ent = `${hourStr}:00 ${timeLapse}`;
      let half = `${hourStr}:30 ${timeLapse}`;
      let hs = i < 10 ? `0${i}` : `${i}`;

      let entHour: Hour = {
        value: `${hs}:00:00`,
        label: ent
      }

      let halfHour: Hour = {
        value: `${hs}:30:00`,
        label: half
      }

      this.hours.push(entHour);
      this.hours.push(halfHour);
    }

    this._route.queryParams.subscribe(params => {
      let idAvi = params['idAvi'];
      this.isNew = idAvi == undefined;

      if(this.isNew){
        this.getData();
      }else{
        this.idAdvice = idAvi;
        this.getAdvice(idAvi);
      }
    });
  }

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

  async getData(){
    try{
      let idEnc = localStorage.getItem('idusuario')!;
      let idDec = await this._encService.desencriptar(idEnc);
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idEnc));
      
      let users: UsersResponse = await lastValueFrom(this._usersProfilesService.getUsers(shortEnc.response.encrypted, 1));
      this.errorStr = users.msg;
      this.hasError = users.error;

      if(this.hasError){
        this.isLoading = false;
      }else{
        let profiles: ProfilesResponse = await lastValueFrom(this._usersProfilesService.getProfiles(shortEnc.response.encrypted, 1));
        this.errorStr = profiles.msg;
        this.hasError = profiles.error;

        if(this.hasError){
          this.isLoading = false;
        }else{
          let profilesGroup: DivisionGroup = {
            name: 'Perfiles',
            division: []
          }

          profiles.response.forEach(profile => {
            let profileDisplay: Division = {
              value: `prof-${profile.IDPERFIL}`,
              viewValue: profile.NOMBREPERFIL
            };

            if(profile.ESTATUS != 'Eliminado') profilesGroup.division.push(profileDisplay);
          });

          this.divisions.push(profilesGroup);
          
          let usersGroup: DivisionGroup = {
            name: 'Usuarios',
            division: []
          };
          
          users.response.forEach(user => {
            let userName = this.buildName(user.NOMBRE, user.APEPAT, user.APEMAT);
            let userID = `user-${user.IDUSUARIO}`;
            
            let userDisplay: Division = {
              value: userID,
              viewValue: userName
            }

            if(user.IDUSUARIO != idDec){
              if(user.ESTATUS == 'Activo') usersGroup.division.push(userDisplay);
            }
          });

          this.divisions.push(usersGroup);
          
          if(this.isNew){
            let initialFiles: TempFileInfo[] = [];
            this.dataSource = new MatTableDataSource(initialFiles);
          }

          this.isLoading = false;
        }
      }
    }catch(error: any){
      this.isLoading = false;
      this.hasError = true;

      if(error.error == undefined || error.error == null){
        this.errorStr = "Ocurrió un error inesperado.";
      }else if(error.error.msg == undefined || error.error.msg == null){
        this.errorStr = "Ocurrió un error inesperado.";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

  async getAdvice(idAvi: string){
    try{
      let aviShort = await lastValueFrom(this._encService.shortEncrypt(idAvi));
      
      let idEnc = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idEnc!));

      let advice: AdviceResponse = await lastValueFrom(this._advicesService.getAdvice(aviShort.response.encrypted, shortEnc.response.encrypted, 1));
      this.adviceTitle.setValue(advice.response.TITULO);
      this.adviceContent.setValue(advice.response.CONTENIDO);

      let audDec = await this._encService.desencriptar(advice.response.AUDIENCIA);
      let audArr = JSON.parse(audDec);
      this.adviceAudience.setValue(audArr);

      let cadu = advice.response.CADUCIDAD;
      let caduArr = cadu.split(' ');
      let caduObj = new Date(`${caduArr[0]}T00:00:00.000`);
      
      this.adviceDate.setValue(caduObj.toISOString());
      this.adviceHour.setValue(caduArr[1]);

      let adjuStr = advice.response.ADJUNTOS;
      let adjuArr = JSON.parse(adjuStr);
      adjuArr.forEach(async (adju: any) => {
        let idDec = await this._encService.desencriptar(adju);
        let short = await lastValueFrom(this._encService.shortEncrypt(adju));
        let file: FinalFileResponse = await lastValueFrom(this._documentManagement.getFileInfo(short.response.encrypted, shortEnc.response.encrypted, 1));

        let fileInfo: TempFileInfo = {
          id: adju,
          name: idDec,
          size: this.formatBytes(file.response.PESO)
        };
        
        this.attached.push(fileInfo);
      });
      this.dataSource = new MatTableDataSource(this.attached);
      
      this.getData();
    }catch(error: any){
      this.isLoading = false;
      this.hasError = true;

      if(error.error == undefined || error.error == null){
        this.errorStr = "Ocurrió un error inesperado.";
      }else if(error.error.msg == undefined || error.error.msg == null){
        this.errorStr = "Ocurrió un error inesperado.";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

  async updateAdvice(){
    let hasError = false;

    if(this.adviceTitle.invalid){
      this.adviceTitle.markAsTouched();
      hasError = true;
    }

    if(this.adviceDate.invalid){
      this.adviceDate.markAsTouched();
      hasError = true;
    }

    if(this.adviceHour.invalid){
      this.adviceHour.markAsTouched();
      hasError = true;
    }

    if(this.adviceContent.invalid){
      this.adviceContent.markAsTouched();
      hasError = true;
    }

    if(this.adviceAudience.invalid){
      this.adviceAudience.markAsTouched();
      hasError = true;
    }

    try{
      let title = this.adviceTitle.value;
      let date = this.adviceDate.value;
      let time = this.adviceHour.value;
      let dateTime = '';
      
      if(typeof date == 'string'){
        dateTime = `${date.split('T')[0]} ${time}`;
      }else{
        let dateOb = new Date(date!);
        dateTime = `${dateOb.toISOString().split('T')[0]} ${time}`;
      }

      let content = this.adviceContent.value;
      let audience = JSON.stringify(this.adviceAudience.value);
      let idUser = localStorage.getItem('idusuario');

      await lastValueFrom(this._advicesService.updateAdvice({
        id_user: idUser,
        id_advice: this.idAdvice,
        linea: 1,
        titulo: title,
        caducidad: dateTime,
        contenido: content,
        audiencia: audience
      }));

      this.openSnackBar('El aviso se actualizó correctamente');
      this._socketService.publishAdvice(this.idAdvice);
      this.goBack(1);
    }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.openSnackBar(msg);
    }
  }

  async downloadFile(idFile: string){
    try{
      let shortAvi = await lastValueFrom(this._encService.shortEncrypt(idFile));
      let idEnc = localStorage.getItem('idusuario');
      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idEnc!));

      let downloadToken = await lastValueFrom(this._advicesService.getDownloadToken(shortAvi.response.encrypted, shortEnc.response.encrypted, 1));
      //this.downloadLink = "http://git.ittec.mx/sam/public/api/download-file///1";
      this.downloadLink = `http://git.ittec.mx/sam/public/api/download-file/${downloadToken.response.TOKEN}/${shortEnc.response.encrypted}/1`;
      console.log(this.downloadLink);
      this.a?.nativeElement.click();
    }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.openSnackBar(msg);
    }
  }

  checkFile(event: any){
    let fileTypes = availableFiles;
    let sizes = Object.keys(fileTypes);
    let extensions = Object.values(fileTypes);
    let maxSizeMB = 0;
      
    let extArr = event.target.files[0].name.split(".").reverse();
    let extStr = extArr[0];

    let i = 0;
    extensions.forEach(ext => {
      let size = parseInt(sizes[i]);

      if(ext.includes(extStr)) maxSizeMB = size;
      i++;
    });

    if(maxSizeMB == 0){
      this.openSnackBar(`Los archivos ${extStr} no están soportados`);
    }else{
      let maxFileSize = 1048576 * maxSizeMB;
      let fileSize = event.target.files[0].size;

      if(fileSize > maxFileSize){
        this.openSnackBar(`El tamaño del archivo supera el límite de ${maxSizeMB} MB`);
      }else{
        let alreadyAttached = false;
        this.attached.forEach(file => {
          alreadyAttached = file.name == event.target.files[0].name && file.size == this.formatBytes(event.target.files[0].size);
        });

        if(alreadyAttached){
          this.openSnackBar("El archivo seleccionado ya fue adjuntado.");
        }else{
          this.isUploading = true;
          this.uploadTmp(event.target.files[0]);
        }
      }
    }
  }

  async uploadTmp(fileData: any){
    try{
      let idUser = localStorage.getItem('idusuario');
      let idUserShort = await lastValueFrom(this._encService.shortEncrypt(idUser!));

      var myFormData = new FormData();
      myFormData.append('file', fileData);
      myFormData.append('id_user', idUserShort.response.encrypted);
      myFormData.append('linea', "1");

      let response = await lastValueFrom(this._systemAdminService.uploadTempFile(myFormData));
      if(response.error){
        this.openSnackBar(response.msg);
      }else{
        let uploadedFile: TempFileInfo = {
          id: response.response.idArchivo,
          name: fileData.name,
          size: this.formatBytes(fileData.size),
        };
        
        this.attached.push(uploadedFile);
        this.dataSource = new MatTableDataSource(this.attached);
        this.isUploading = false;
      }
    }catch(error: any){
      this.isUploading = false;
      let msg = "";
      if(error.error == undefined){
        msg = 'Ocurrió un error insperado.';
      }else if(error.error.msg == undefined){
        msg = 'Ocurrió un error insperado.';
      }else{
        msg = error.error.msg;
      }

      this.openSnackBar(msg);
    }
  }

  buildName(nomb: string, appa: string, apma?: string): string{
    if(apma == '' || apma == null || apma == undefined){
      return `${nomb} ${appa}`;
    }else{
      return `${nomb} ${appa} ${apma}`;
    }
  }

  applyFilter(event: Event){
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource!.filter = filterValue.trim().toLowerCase();

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

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

  async deleteFile(id: string){
    try{
      let idUser = localStorage.getItem('idusuario');
      let idUserShort = await lastValueFrom(this._encService.shortEncrypt(idUser!));

      let response = await lastValueFrom(this._systemAdminService.deleteTempFile({
        'id_user': idUserShort.response.encrypted,
        'id_file': id,
        'linea': 1,
      }));

      if(response.error){
        this.openSnackBar(response.msg);
      }else{
        let attachedAux: TempFileInfo[] = [];
        this.attached.forEach(file => {
          if(file.id != id) attachedAux.push(file);
        });

        this.attached = attachedAux;
        this.dataSource = new MatTableDataSource(this.attached);
      }
    }catch(error: any){
      this.isUploading = false;
      let msg = "";
      if(error.error == undefined){
        msg = 'Ocurrió un error insperado.';
      }else if(error.error.msg == undefined){
        msg = 'Ocurrió un error insperado.';
      }else{
        msg = error.error.msg;
      }

      this.openSnackBar(msg);
    }
  }

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

  async publishAdvice(){
    let hasError = false;

    if(this.adviceTitle.invalid){
      this.adviceTitle.markAsTouched();
      hasError = true;
    }

    if(this.adviceDate.invalid){
      this.adviceDate.markAsTouched();
      hasError = true;
    }

    if(this.adviceHour.invalid){
      this.adviceHour.markAsTouched();
      hasError = true;
    }

    if(this.adviceContent.invalid){
      this.adviceContent.markAsTouched();
      hasError = true;
    }

    if(this.adviceAudience.invalid){
      this.adviceAudience.markAsTouched();
      hasError = true;
    }

    if(hasError){
      this.openDialog('Antes de continuar debe completar los campos señalados.');
    }else{
      let title = this.adviceTitle.value;
      let date = this.adviceDate.value;
      let content = this.adviceContent.value;
      let audience = this.adviceAudience.value;
      let time = this.adviceHour.value;

      let dateObj = new Date(date!);
      let dateStr = `${dateObj.getFullYear()}-${this.buildMonth(dateObj.getMonth())}-${this.buildDay(dateObj.getDate())}`;
      let dateTimeStr = `${dateStr} ${time}`;
      let audienceStr = JSON.stringify(audience);
      let attachedStr = JSON.stringify(this.attached);

      let idEnc = localStorage.getItem('idusuario');
      let body = {
        id_user: idEnc,
        linea: 1,
        titulo: title,
        caducidad: dateTimeStr,
        contenido: content,
        audiencia: audienceStr,
        archivos: attachedStr
      };

      try{
        let response = await lastValueFrom(this._advicesService.publishAdvice(body));
        let idav = response.response.idav;
        
        this._socketService.publishAdvice(idav);
        
        this.openSnackBar('Aviso publicado correctamente');
      }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.openSnackBar(msg);
      }
    }
  }

  buildMonth(month: number): string{
    let numMonth = month + 1;

    if(numMonth < 10){
      return `0${numMonth}`;
    }else{
      return `${numMonth}`;
    }
  }

  buildDay(day: number): string{
    if(day < 10){
      return `0${day}`;
    }else{
      return `${day}`;
    }
  }

  openDialog(msg: string){
    this._dialg.open(AlertComponent, {
      width: '300px',
      data: {
        icon: "error",
        title: '¡Error!',
        description: msg
      }
    });
  }

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