import { Injectable } from '@angular/core';
import { EncService } from './enc.service';
import { PermissionsInterface } from '../interfaces/permissions.interface';
import { Router } from '@angular/router';
import { ResourcesService } from './resources.service';
import { lastValueFrom } from 'rxjs';
import { ModulesService } from './modules.service';
import { ModulesInterface } from '../interfaces/modules.interface';

export const HEX_VALUES = {
  '0': 0, '1': 1, '2': 2,  '3': 3,  '4': 4,  '5': 5,  '6': 6,  '7': 7, 
  '8': 8, '9': 9, 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15
};
export const DEC_VALUES = [
  '0', '1', '2', '3', '4', '5', '6', '7',
  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
];
@Injectable({
  providedIn: 'root'
})
export class FunctionsService {
  MONTHS = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
  DAYS = ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'];

  constructor(
    private _encService: EncService,
    private _router: Router,
    private _resourcesService: ResourcesService,
    private _modulesService: ModulesService,
  ) { }

  orderDate(date: string): string {
    let dateTimeArr = date.split(' ');
    if(dateTimeArr[0] == undefined || dateTimeArr[0] == 'undefined'){
      return '';
    }else if(dateTimeArr[0].includes('T')){
      let dateJSArr = dateTimeArr[0].split('T');
      dateTimeArr[0] = dateJSArr[0];
    }

    let dateArr = dateTimeArr[0].split('-');
    dateArr = dateArr.reverse();

    let dateStr = dateArr.join('-');
    let timeArr = dateTimeArr[1].split(':');
    let hour = parseInt(timeArr[0]);
    let period = hour < 12 ? 'AM' : 'PM';

    if(hour > 12) hour = hour - 12;
    let hourStr = hour < 10 ? `0${hour}` : `${hour}`;

    timeArr[0] = hourStr;
    timeArr.pop();
    let timeStr = timeArr.join(':');
    
    return `${dateStr} ${timeStr} ${period}`;
  }

  notificationDate(date: string): string{
    let dateObj = new Date(date);
    let now = new Date();
    let diff = now.getTime() - dateObj.getTime();

    let diffInSecs = diff / 1000;
    if(diffInSecs < 60){
      return "Hace un momento";
    }

    let diffInMins = diffInSecs / 60;
    if(diffInMins >= 1 && diffInMins < 2){
      return "Hace un minuto";
    }else if(diffInMins < 60){
      let minutes = Math.trunc(diffInMins);
      return `Hace ${minutes} minutos`;
    }

    let diffInHours = diffInMins / 60;
    if(diffInHours >= 1 && diffInHours < 2){
      return "Hace una hora";
    }else if(diffInHours < 24){
      let hours = Math.trunc(diffInHours);
      return `Hace ${hours} horas`;
    }

    let diffInDays = diffInHours / 24;
    if(diffInDays >= 1 && diffInDays < 2){
      return "Ayer";
    }

    let dateTimeArr = date.split(' ');
    let dateArr = dateTimeArr[0].split('-').reverse();
    let dateStr = dateArr.join('/');

    let timeArr = dateTimeArr[1].split(':');
    let hour = parseInt(timeArr[0]);
    let period = hour < 12 ? 'AM' : 'PM';

    hour = hour > 12 ? hour - 12 : hour;
    return `${dateStr} ${hour}:${timeArr[1]} ${period}`;
  }

  buildHumanDate(date: string): string{
    let dateArr = date.split('-').reverse();
    let monthInd = parseInt(dateArr[1]) - 1;
    
    return `${dateArr[0]} de ${this.MONTHS[monthInd]} del ${dateArr[2]}`;
  }

  buildHumanDateWithDay(date: string): string{
    let dateObj = new Date(date);
    return `${this.DAYS[dateObj.getDay()]} ${dateObj.getDate()} de ${this.MONTHS[dateObj.getMonth()]} del ${dateObj.getFullYear()}`;
  }

  buildName(no: string, ap: string, am: string | null | undefined): string{
    let name = `${no} ${ap}`;
    if(am != "" && am != undefined && am != null){
      name += ` ${am}`;
    }
    return name;
  }



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

  activatorCustomRepeat(value: string): string{
    if(value == ''){
      return '';
    }

    let resObj = JSON.parse(value);
    let repeatEvery = resObj.repeatEvery.split('|');
    let customRepeat = 'Repetir cada ';

    if(repeatEvery[0] != "1"){
      customRepeat += repeatEvery[0];
    }

    switch(repeatEvery[1]){
      case "0": customRepeat += repeatEvery[0] != "1" ? ' días' : ' día'; break;
      case "1": customRepeat += repeatEvery[0] != "1" ? ' semanas' : ' semana'; break;
      case "2": customRepeat += repeatEvery[0] != "1" ? ' meses' : ' mes'; break;
      case "3": customRepeat += repeatEvery[0] != "1" ? ' años' : ' año'; break;
    }

    let days = 0;
    let daysValues = Object.values(resObj.repeatOn);
    let daysStr = '';
    let cont = 0;
    
    daysValues.forEach(val => {
      if(val){
        daysStr += `${this.DAYS[cont]}, `; 
        days++;
      }

      cont++;
    });

    daysStr = daysStr.substring(0, daysStr.length - 2);
    
    if(days > 1){
      customRepeat += ' los días: ';
    }else{
      customRepeat += ' el día: ';
    }

    customRepeat += daysStr;

    let endsAt = resObj.endsAt.split('|');
    if(endsAt[0] == 'O'){
      let dateArr = endsAt[1].split('-').reverse();
      customRepeat += '. Finaliza el ' + dateArr[0] + ' de ' + this.MONTHS[parseInt(dateArr[1])] + ' del ' + dateArr[2] + '.';
    }else if(endsAt[0] == 'A'){
      let after = endsAt[2];
      customRepeat += '. Finaliza después de ' + after + ' repeti';

      if(after == '1'){
        customRepeat += 'ción.';
      }else{
        customRepeat += 'ciones.';
      }
    }

    return `${customRepeat.replace('  ', ' ')}||${value}`;
  }

  activatorRepeat(repeat: string, dateStr: string): string{
    let dateObj = new Date(dateStr);
    if(repeat == 'NR'){
      return 'No se repite';
    }else if(repeat == 'SE'){
      return `Semanalmente los ${this.DAYS[dateObj.getDay()]}`;
    }else if(repeat == 'ME'){
      return `Mensualmente los días ${dateObj.getDate()}`;
    }else if(repeat == 'AN'){
      return `Anualmente el ${dateObj.getDate()} de ${this.MONTHS[dateObj.getMonth()]}`;
    }else if(repeat == 'TD'){
      return `Todos los días a partir del ${this.DAYS[dateObj.getDay()]} ${dateObj.getDate()} de ${this.MONTHS[dateObj.getMonth()]} del ${dateObj.getFullYear()}`
    }else if(repeat == 'PE'){
      return 'Personalizado...';
    }else{
      return 'Desconocido';
    }
  }

  activatorComparision(comparision: string): string{
    if(comparision == 'AC'){
      return 'Acumulado';
    }else if(comparision == 'UR'){
      return 'Último registro';
    }else{
      return 'Desconocido';
    }
  }

  getDateTimeHour(dateTime: string): string{
    let dateTimeArr = dateTime.split(' ');
    let timeArr = dateTimeArr[1].split(':');
    let hour = parseInt(timeArr[0]);
    let period = hour < 12 ? 'AM' : 'PM';
  
    hour = hour > 12 ? hour - 12 : hour;
    let hourStr = hour < 10 ? `0${hour}` : `${hour}`;
    
    return `${hourStr}:${timeArr[1]} ${period}`;
  }

  async processPermissions(permissions: PermissionsInterface[]): Promise<PermissionsInterface[]>{
    let processedPermissions: PermissionsInterface[] = [];
    for(const item of permissions){
      let isEncrypted = await this._encService.isEncrypted(item.id);
      if(isEncrypted){
        item.id = await this._encService.decrypt(item.id);
      }

      if(item.children != undefined && item.children.length > 0){
        let processedChildren = await this.processPermissions(item.children);
        item.children = processedChildren;
      }

      processedPermissions.push(item);
    }

    return processedPermissions;
  }

  sanitizeIconName(name: string): string{
    let iconName = '';
    iconName = name.replace('.svg', '').toLowerCase();

    let iconNameArr = iconName.split(' ');
    iconName = '';

    let cont = 0;
    for(const word of iconNameArr){
      if(word != ''){
        if(cont > 0){
          let capitalizedWord = word[0].toUpperCase() + word.slice(1);
          iconName += capitalizedWord;
        }else{
          iconName += word;
        }
        cont++;
      }
    }
    
    return iconName;
  }

  orderPRTGTimestamp(date: string): string{
    let dateObj = new Date(date);

    let year = dateObj.getFullYear().toString().substring(2);
    let month = dateObj.getMonth() + 1 < 10 ? `0${dateObj.getMonth() + 1}` : `${dateObj.getMonth() + 1}`;
    let day = dateObj.getDate() < 10 ? `0${dateObj.getDate()}` : `${dateObj.getDate()}`;

    let hour = dateObj.getHours() < 10 ? `0${dateObj.getHours()}` : `${dateObj.getHours()}`;
    let minutes = dateObj.getMinutes() < 10 ? `0${dateObj.getMinutes()}` : `${dateObj.getMinutes()}`;
    let seconds = dateObj.getSeconds() < 10 ? `0${dateObj.getSeconds()}` : `${dateObj.getSeconds()}`;
    
    return `${year}${month}${day} ${hour}:${minutes}:${seconds}`;
  }

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

  convertFullHourToHumanHour(hour: string): string{
    let hourArr = hour.split(':');
    if(hourArr.length == 3){
      let hourNum = parseInt(hourArr[0]);
      let period = hourNum < 12 ? 'AM' : 'PM';
  
      if(period == 'PM'){
        hourNum = hourNum > 12 ? hourNum - 12 : hourNum;
      }
  
      let hourStr = hourNum < 10 ? `0${hourNum}` : `${hourNum}`;
      return `${hourStr}:${hourArr[1]} ${period}`;
    }
    
    return "";
  }

  convertHumanHourToFullHour(hour: string): string{
    let timeArr = hour.split(' ');
    if(timeArr.length == 2){
      let hourArr = timeArr[0].split(':');
      if(hourArr.length == 2){
        let hourNum = parseInt(hourArr[0]);
        if(timeArr[1] == 'PM'){
          hourNum = hourNum < 12 ? hourNum + 12 : hourNum;
        }

        let hourStr = hourNum < 10 ? `0${hourNum}` : `${hourNum}`;
        return `${hourStr}:${hourArr[1]}:00`;
      }

      return "";
    }
    
    return "";
  }

  buildLastUpdate(dateTime: string): string{
    let dateTimeArr = dateTime.split(' ');
    if(dateTimeArr.length != 2) return '';

    let dateArr = dateTimeArr[0].split('-');
    let dateStr = '';
    
    if(dateArr.length != 3) return '';
    let monthInd = parseInt(dateArr[1]) - 1;
    let monthStr = this.MONTHS[monthInd];

    dateArr = dateArr.reverse();
    dateStr = `${dateArr[0]} de ${monthStr} del ${dateArr[2]}`;

    let timeArr = dateTimeArr[1].split(':');
    let hourNum = parseInt(timeArr[0]);
    let period = hourNum > 12 ? 'PM' : 'AM';
    let hour = hourNum > 12 ? hourNum - 12 : hourNum;
    let hourStr = hour < 10 ? `0${hour}` : `${hour}`;
    
    return `${dateStr} a las ${hourStr}:${timeArr[1]} ${period}`;
  }

  async consultModuleStatus(idModule: string){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let modules: ModulesInterface = await lastValueFrom(this._modulesService.getModules(idUser, 1));

      if(modules.error){
        this._resourcesService.openSnackBar(modules.msg);
      }else{
        for(const module of modules.response){
          let idModuleDec = await this._encService.decrypt(module.ID_MODULO);
          if(idModuleDec == idModule){
            if(!module.ESTADO_MODULO){
              this._resourcesService.openSnackBar('El módulo al que intenta acceder se encuentra apagado.');
              this._router.navigate(['sam/home']);
            }
          }
        }
      }
    }catch(error: any){
      if(error.error == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado (379).');
      }else if(error.error.msg == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado (381).');
      }else{
        this._resourcesService.openSnackBar(error.error.msg);
      }
    }
  }

  colorHEXtoRGB(color: string): string{
    let rHex = color.substring(0, 2);
    let gHex = color.substring(2, 4);
    let bHex = color.substring(4);
    let rInt = 0;
    let gInt = 0;
    let bInt = 0;

    for(let i = 0; i < rHex.length; i++){
      let hexChar = rHex.charAt(i);
      let intChar = HEX_VALUES[hexChar as never];
      let hexPosition = rHex.length - (i + 1);
      let positionValue = Math.pow(16, hexPosition) * intChar;

      rInt += positionValue;
    }

    for(let i = 0; i < gHex.length; i++){
      let hexChar = gHex.charAt(i);
      let intChar = HEX_VALUES[hexChar as never];
      let hexPosition = gHex.length - (i + 1);
      let positionValue = Math.pow(16, hexPosition) * intChar;

      gInt += positionValue;
    }

    for(let i = 0; i < bHex.length; i++){
      let hexChar = bHex.charAt(i);
      let intChar = HEX_VALUES[hexChar as never];
      let hexPosition = bHex.length - (i + 1);
      let positionValue = Math.pow(16, hexPosition) * intChar;

      bInt += positionValue;
    }

    return `${rInt}, ${gInt}, ${bInt}`;
  }

  colorRGBtoHEX(color: string): string{
    let colorArr = color.split(', ');
    let rInt = parseInt(colorArr[0]);
    let gInt = parseInt(colorArr[1]);
    let bInt = parseInt(colorArr[2]);
    let rHex = "";
    let gHex = "";
    let bHex = "";

    let resto = rInt;
    let test = 0;
    
    do{
      let rDiv = Math.floor(resto / 16);
      resto = resto % 16;
      console.log(rDiv);
      console.log(resto);

      test++;
    }while(test < 3);

    console.log(rInt, gInt, bInt);
    return '';
  }
}
