import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { UserResponse, UsersResponse } from '../../../../interfaces/users.interface';
import { TempFileInfo } from '../../../../interfaces/temp-file-info.interface';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatchErrors } from '../../../users-profiles/profiles-admin/new-profile/new-profile.component';
import { FormControl, Validators } from '@angular/forms';
import { UsersProfilesService } from '../../../../services/users-profiles.service';
import { DOCUMENT } from '@angular/common';
import { EncService } from '../../../../services/enc.service';
import { MatDialog } from '@angular/material/dialog';
import { AdvicesService } from '../../../../services/advices.service';
import { SocketService } from '../../../../services/socket.service';
import { ActivatedRoute, Router } from '@angular/router';
import { GdelService } from '../../../../services/gdel.service';
import { ResourcesService } from '../../../../services/resources.service';
import { FunctionsService } from '../../../../services/functions.service';
import { lastValueFrom } from 'rxjs';
import { ProfilesResponse } from '../../../../interfaces/profiles.interface';
import { Permissions } from '../../../../interfaces/permissions.interface';
import { AdviceResponse } from '../../../../interfaces/advice.interface';
import { UserConsultResponse } from '../../../../interfaces/user.interface';
import { ProfileInterface } from '../../../../interfaces/profile.interface';
import { apiTemp, availableFiles } from '../../../../../environments/environment.prod';
import { AlertComponent } from '../../../resources/dialogs/alert/alert.component';

interface DivisionGroup{
  name: string;
  division: Division[];
}
interface Division{
  value: string;
  viewValue: string;
}
interface Hour{
  value: string;
  label: string;
}
@Component({
    selector: 'app-new-advice',
    templateUrl: './new-advice.component.html',
    styleUrl: './new-advice.component.css',
    standalone: false
})
export class NewAdviceComponent implements OnInit {
  isLoading: boolean;
  isUploading: boolean;
  isNew: boolean;
  hasError: boolean;
  downloadEnabled: boolean;
  errorStr: string;
  downloadLink: string;
  idAdvice: string;
  users: UserResponse[];
  divisions: DivisionGroup[];
  attached: TempFileInfo[];
  hours: Hour[];
  screenSize: number;
  audience: any[];
  now: Date;

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

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  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([] as string[], Validators.required);

  btnSmall: boolean = false;
  txtBuscador:string;

  constructor(
    @Inject(DOCUMENT) private _document: Document,
    private _usersProfilesService: UsersProfilesService,
    private _encService: EncService,
    private _dialg: MatDialog,
    private _advicesService: AdvicesService,
    private _socketService: SocketService,
    private _route: ActivatedRoute,
    private _gdelService: GdelService,
    private _router: Router,
    private _resourcesService: ResourcesService,
    private _functionsService: FunctionsService,
  ) {
    this.isLoading = true;
    this.isUploading = false;
    this.hasError = false;
    this.isNew = false;
    this.downloadEnabled = true;
    this.errorStr = "";
    this.downloadLink = "";
    this.idAdvice = "";
    this.users = [];
    this.divisions = [];
    this.attached = [];
    this.hours = [];
    this.txtBuscador = '';
    this.screenSize = window.innerWidth;
    this.audience = [];
    this.now = new Date();
  }

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

    this._socketService.refreshPermissions().subscribe(async (profUpdEnc) => {
      try{
        let idUser = localStorage.getItem('idusuario')!;
        let usrInfo: UserConsultResponse = await lastValueFrom(this._usersProfilesService.getUser(idUser, idUser, 1));
        
        if(usrInfo.error){
          this._resourcesService.openSnackBar('ERR_NPE000: Ocurrió un error inesperado.');
        }else{
          let idProfDec = await this._encService.decrypt(usrInfo.response.PERFIL);
          let currentProfile = await this._encService.decrypt(localStorage.getItem('perfil')!);

          if(idProfDec != currentProfile){
            this._router.navigate(['/sam/home']);
            return;
          }
          
          let profileUpdated = await this._encService.decrypt(`${profUpdEnc}`);
          if(profileUpdated == currentProfile){
            let profile = localStorage.getItem('perfil')!;
            let profInfo: ProfileInterface = await lastValueFrom(this._usersProfilesService.getProfile(
              profile,
              idUser,
              1
            ));

            let permArr = await this._functionsService.processPermissions(profInfo.response.PERMISOS.permissions);
            let modPerm = permArr.filter(item => item.id == 'S002V01M01ADSI');
            if(modPerm.length > 0){
              let funPerm = modPerm[0].children.filter(item => item.id == 'S002V01F03CRAV');
              if(funPerm.length > 0){
                let adviceAudience = funPerm[0].children.filter(item => item.id == 'S002V01P04CAPU');
                if(adviceAudience.length > 0){
                  if(!this.isNew && adviceAudience[0].access == 0){
                    this.adviceAudience.disable();
                  }else{
                    this.adviceAudience.enable();
                  }
                }
              }
            }
          }
        }
      }catch(error: any){
        if(error.error == undefined){
          this._resourcesService.openSnackBar('ERR_PAD001: Ocurrió un error inesperado.');
        }else if(error.error.msg == undefined){
          this._resourcesService.openSnackBar('ERR_PAD002: Ocurrió un error inesperado.');
        }else{
          this._resourcesService.openSnackBar(`ERR_PAD003: ${error.error.msg}`);
        }
      }
    });
  }

  async getData(){
    try{
      let idEnc = localStorage.getItem('idusuario')!;
      let idDec = await this._encService.decrypt(idEnc);

      let users: UsersResponse = await lastValueFrom(this._usersProfilesService.getUsers(idEnc, 1));
      this.errorStr = users.msg;
      this.hasError = users.error;

      if(!this.hasError){
        let profiles: ProfilesResponse = await lastValueFrom(this._usersProfilesService.getProfiles(idEnc, 1));
        this.errorStr = profiles.msg;
        this.hasError = profiles.error;

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

          for(const profile of profiles.response){
            let idProfileDec = await this._encService.decrypt(profile.IDPERFIL);
            let profileValue = `prof-${profile.IDPERFIL}`;
            let profileFilt = this.audience.filter(item => item.id == idProfileDec && item.type == 'prof');

            if(profileFilt.length > 0){
              let audArr = this.adviceAudience.value!;
              audArr.push(profileValue);
            }
            
            let profileDisplay: Division = {
              value: profileValue,
              viewValue: profile.NOMBREPERFIL
            };

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

          this.divisions.push(profilesGroup);
          let usersGroup: DivisionGroup = {
            name: 'Usuarios',
            division: []
          };

          for(const user of users.response){
            let userName = this.buildName(user.NOMBRE, user.APEPAT, user.APEMAT);
            let userValue = `user-${user.IDUSUARIO}`;
            let idUserDec = await this._encService.decrypt(user.IDUSUARIO);
            let userFilt = this.audience.filter(item => item.id == idUserDec && item.type == 'user');

            if(userFilt.length > 0){
              let audArr = this.adviceAudience.value!;
              audArr.push(userValue);
            }

            let userDisplay: Division = {
              value: userValue,
              viewValue: userName
            }

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

          this.divisions.push(usersGroup);

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

          let permissionsEnc = localStorage.getItem('permisos');
          let permissionsDec = await this._encService.decrypt(permissionsEnc!);
          let permissionsArr: Permissions = JSON.parse(permissionsDec);

          let modPerm = permissionsArr.permissions.filter(item => item.id == 'S002V01M01ADSI')[0];
          let funPerm = modPerm.children.filter(item => item.id == 'S002V01F03CRAV')[0];

          if(!this.isNew && funPerm.children.filter(item => item.id == 'S002V01P04CAPU')[0].access == 0){
            this.adviceAudience.disable();
          }else{
            this.adviceAudience.enable();
          }
        }
      }

      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 (1).";
      }else if(error.error.msg == undefined || error.error.msg == null){
        this.errorStr = "Ocurrió un error inesperado (2).";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

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

  async getAdvice(idAvi: string){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let advice: AdviceResponse = await lastValueFrom(this._advicesService.getAdvice(idAvi, idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        this.adviceTitle.setValue(advice.response.TITULO);
        this.adviceContent.setValue(advice.response.CONTENIDO);

        let audienceArr = JSON.parse(advice.response.AUDIENCIA);
        for(const item of audienceArr){
          let idDec = await this._encService.decrypt(item.id);
          this.audience.push({
            id: idDec,
            type: item.type,
          });
        }

        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 adjuArr = JSON.parse(advice.response.ADJUNTOS);
        for(const item of adjuArr){
          let fileInfo: TempFileInfo = {
            id: item.id,
            name: item.name,
            size: this.formatBytes(item.size)
          };
  
          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){
        console.log(error);
        this.errorStr = "Ocurrió un error inesperado (3).";
      }else if(error.error.msg == undefined || error.error.msg == null){
        this.errorStr = "Ocurrió un error inesperado (4).";
      }else{
        this.errorStr = error.error.msg;
      }
    }
  }

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

  public onResize():void {
    this.screenSize = window.innerWidth;
  }

  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._resourcesService.openSnackBar(`Los archivos ${extStr} no están soportados`);
    }else{
      let maxFileSize = 1048576 * maxSizeMB;
      let fileSize = event.target.files[0].size;

      if(fileSize > maxFileSize){
        this._resourcesService.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._resourcesService.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 formData = new FormData();

      formData.append('file', fileData);
      formData.append('id_user', idUser);
      formData.append('linea', "1");

      let response = await lastValueFrom(this._gdelService.uploadTempFile(formData));

      if(response.error){
        this._resourcesService.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._resourcesService.openSnackBar(msg);
    }
  }

  async deleteFile(id: string){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let response = await lastValueFrom(this._gdelService.deleteTempFile({
        'id_user': idUser,
        'id_file': id,
        'linea': 1,
      }));

      if(response.error){
        this._resourcesService.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._resourcesService.openSnackBar(msg);
    }
  }

  async downloadFile(idFile: string){
    try{
      this.downloadEnabled = false;

      let idEnc = localStorage.getItem('idusuario')!;
      let downloadToken = await lastValueFrom(this._advicesService.getDownloadToken(idFile, idEnc, 1));
      let download = this._document.getElementById(`download-${idFile}`) as HTMLAnchorElement;

      let idDec = await this._encService.decrypt(idFile);

      download.href = `${apiTemp}download-file/${downloadToken.response.TOKEN}/${idEnc}/1`;
      download.download = idDec;
      download.click();

      this.downloadEnabled = true;
    }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._resourcesService.openSnackBar(msg);
      this.downloadEnabled = true;
    }
  }

  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._resourcesService.openSnackBar('Aviso publicado correctamente');
        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._resourcesService.openSnackBar(msg);
      }
    }
  }

  openDialog(msg: string){
    this._dialg.open(AlertComponent, {
      width: '300px',
      data: {
        icon: "error",
        title: '¡Error!',
        description: 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}`;
    }
  }

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

  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._resourcesService.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._resourcesService.openSnackBar(msg);
    }
  }
}
