import { Injectable } from '@angular/core';
import { EncService } from './enc.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { docClassification } from '../../environments/environment.prod';
import { MatTableDataSource } from '@angular/material/table';
import { RequestUserNumberLine } from '../interfaces/response-data';
import { lastValueFrom } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ResourcesService {
  arrMonth: Array<string>;
  arrMonthLabel: Array<string>;
  weekDay: Array<any>;
  weekDays: Array<string>;
  
  constructor(
    private _encService: EncService,
    private _matSnackBar: MatSnackBar,
    private _router: Router,
    private _httpClient: HttpClient,
  ) {
    this.arrMonth = [
      '01', '02', '03', '04',
      '05', '06', '07', '08',
      '09', '10', '11', '12'
    ];

    this.arrMonthLabel = [
      'Enero','Febrero','Marzo','Abril',
      'Mayo','Junio','Julio','Agosto',
      'Septiembre','Octubre','Noviembre','Diciembre'
    ];

    this.weekDay = [
      { week: 'Domingo', acronym: 'Dom' },
      { week: 'Lunes', acronym: 'Lun' },
      { week: 'Martes', acronym: 'Mar' },
      { week: 'Miércoles', acronym: 'Mié' },
      { week: 'Jueves', acronym: 'Jue' },
      { week: 'Viernes', acronym: 'Vie' },
      { week:  'Sábado', acronym: 'Sáb' }
    ];

    this.weekDays = ['Domingos', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábados'];
  }

  public checkErrors(httpErrorResponse: HttpErrorResponse) {
    console.log(httpErrorResponse);

    if (httpErrorResponse.ok === false && httpErrorResponse.error.hasOwnProperty('error')) {
      let responseData: ResponseData = httpErrorResponse.error;
      if (responseData.error) {

        if (typeof(responseData.response) === 'object') {
          const KEYS: Array<string> = Object.keys(responseData.response);

          if (KEYS.length > 0) {
            const DATAERROR: string = KEYS.toString().replace(',', ', ').trim();
            this.openSnackBar(`Ocurrió un error en ${ KEYS.length > 1 ? 'los campos' : 'el campo'} ${DATAERROR}`);
          } else {
            console.log('test');
            if (responseData.msg.includes('ERR_GLB_USU003')) {
              return { reload: true }
            }
            this.openSnackBar(`${responseData.msg}`);
          }

        } else if (typeof(responseData.response) === 'string'){
          this.openSnackBar(`${responseData.msg} (${responseData.response})`);
        } else {
          this.openSnackBar('Ha ocurrido un error inesperado, favor de comunicarse con el departamento de TI.');
        }
      } else {
        this.openSnackBar(`${responseData.msg}`);
      }
    } else if (httpErrorResponse.ok === false && httpErrorResponse.error.hasOwnProperty('message') && httpErrorResponse.error.hasOwnProperty('exception')) {
      const errorException: ResponseErrorException = httpErrorResponse.error;
      const arrController: Array<string> = errorException.file.split('\\');
      const controller: string = arrController[arrController.length-1];
      this.openSnackBar(`Ocurrió un error inesperado: ${errorException.message} en ${controller}:${errorException.line}`);
    } else if (httpErrorResponse.message.includes("Http failure response for") && httpErrorResponse.statusText === "Unknown Error") {
      this.openSnackBar('No fue posible conectar con el servidor del SAM, favor de contactar al departamento de TI.');
    } else if (httpErrorResponse.status == 408){
      this.openSnackBar('Su conexión no fue apta para conectar con los servidores del SAM.');
    } else {
      this.openSnackBar('Ocurrió un error inesperado, favor de contactar al departamento de TI.');
    }

    return null
  }

  public checkErrorsStr(httpErrorResponse: HttpErrorResponse): string {
    console.log(httpErrorResponse);

    if (httpErrorResponse.ok === false && httpErrorResponse.error.hasOwnProperty('error')) {
      let responseData: ResponseData = httpErrorResponse.error;
      if (responseData.error) {

        if (typeof(responseData.response) === 'object' ) {
          const KEYS: Array<string> = Object.keys(responseData.response);

          if (KEYS.length > 0) {
            const DATAERROR: string = KEYS.toString().replace(',', ', ').trim();
            return `Ocurrió un error en ${ KEYS.length > 1 ? 'los campos' : 'el campo'} ${DATAERROR}`;
          } else {
            return `${responseData.msg}`;
          }

        } else if (typeof(responseData.response) === 'string'){
          return `${responseData.msg} (${responseData.response})`;
        } else {
          return 'Ha ocurrido un error inesperado, favor de comunicarse con el departamento de TI.';
        }
      } else {
        return `${responseData.msg}`;
      }
    } else if (httpErrorResponse.ok === false && httpErrorResponse.error.hasOwnProperty('message') && httpErrorResponse.error.hasOwnProperty('exception')) {
      const errorException: ResponseErrorException = httpErrorResponse.error;
      const arrController: Array<string> = errorException.file.split('\\');
      const controller: string = arrController[arrController.length-1];
      return `Ocurrió un error inesperado: ${errorException.message} en ${controller}:${errorException.line}`;

    } else if (httpErrorResponse.message.includes("Http failure response for") && httpErrorResponse.statusText === "Unknown Error") {
      return 'No fue posible conectar con el servidor del SAM, favor de contactar al departamento de TI.';

    } else if (httpErrorResponse.status == 408){
      return 'Su conexión no fue apta para conectar con los servidores del SAM.';

    } else {
      return 'Ocurrió un error inesperado, favor de contactar al departamento de TI.';
    }
  }

  // Verifica que el id del usuario se encuentre registrado en el localstorage
  public getUser(): string {
    let idusuario = localStorage.getItem('idusuario')!;
    if (idusuario !== null && idusuario !== undefined) {
      return idusuario;
    } else {
      this.openSnackBarAfter('Ocurrió un error al obtener el usuario, inicie sesión de nuevo.');
      localStorage.clear();
      this._router.navigate(['login']);
      return '';
    }
  }

  public async getDecryptUser(): Promise<string> {
    const IDUSUARIO = localStorage.getItem('idusuario')!;
    if (IDUSUARIO !== null && IDUSUARIO !== undefined) {
      const USER_DEC = await this._encService.decrypt(IDUSUARIO);
      return USER_DEC;
    } else {
      this.openSnackBarAfter('Ocurrió un error al obtener el usuario, inicie sesión de nuevo.');
      localStorage.clear();
      this._router.navigate(['login']);
      return '';
    }
  }

  public getToken(): string {
    let token: string | null = localStorage.getItem('token');
    if (token !== null && token !== undefined) {
      return token;
    } else {
      this.openSnackBarAfter('Ocurrió un error al obtener el token, favor de iniciar sesión nuevamente.');
      localStorage.clear();
      this._router.navigate(['login']);
      return '';
    }
  }

  public getLineNumber(): number {
    return 1;
  }

  // Ejecuta un mensaje
  public openSnackBar(message: string, action: string = "Cerrar", timer: number = 7000) {
    this._matSnackBar.open(message, action, {
      duration: timer
    });
  }

  //Ejecuta un mensaje después de otro mensaje
  public openSnackBarAfter(message: string, action: string = "Cerrar", timer: number = 7000) {
    setTimeout(() => {
      this._matSnackBar.open(message, action, {
        duration: timer
      });
    }, 1500)
  }

  // Obtiene la fecha actual en formato DD-MM-YYYY
  public getDateFormat(): string {
    let dateFormat: Date = new Date();
    return `${dateFormat.getDate()}-${this.arrMonth[dateFormat.getMonth()]}-${dateFormat.getFullYear()}`;
  }

  // Obtiene una fecha de tipo Date y regresa una fecha en formato YYY-MM-DD
  public getDateFormatCalendar(date:Date): string {
    let day: string = date.getDate().toString();
    let month: string = this.arrMonth[date.getMonth()];
    let year: string = date.getFullYear().toString();
    return `${year}-${month}-${day}`;
  }

  public getDateFormatCalendarFormat(date:Date): string {
    let day: string = date.getDate().toString();
    let month: string = this.arrMonth[date.getMonth()];
    let year: string = date.getFullYear().toString();
    return `${day}-${month}-${year}`;
  }

  // Obtiene dos fechas y regresa la fecha que esté disponible
  public formatDate(dateRegister:string | null | undefined, dateUpdate:string | undefined | null): string {
    let date:string = '';
    if (typeof dateRegister === 'string' && dateUpdate === null) {
      date = dateRegister;
    } else if (typeof dateRegister === 'string' && dateUpdate !== null && dateUpdate !== undefined) {
      date = dateUpdate;
    } else {
      return 'ERR';
    }
    let arrDateTime:Array<string> = date.split(' ');
    let arrDate:Array<string> = arrDateTime[0].split('-');
    return `${arrDate[2]}-${arrDate[1]}-${arrDate[0]} ${arrDateTime[1]}`;
  }

  // Obtiene una fecha de tipo String de formato DATETIME y regresa una fecha en formato DD-MM-YYYY HH:MM:SS
  public formatOnlyDatetime(date:string): string {
    let arrDateHour:Array<string> = date.split(' ');
    let arrDate:Array<string> = arrDateHour[0].split('-');
    return `${arrDate[2]}-${arrDate[1]}-${arrDate[0]} ${arrDateHour[1]}`;
  }
  
  // Obtiene una fecha tipo String de formato YYYY-MM-DD y regresa una fecha en formato DD-MM-YYYY
  public formatOnlyDate(date:string):string {
    let arrDate:Array<string> = date.split('-');
    return `${arrDate[2]}-${arrDate[1]}-${arrDate[0]}`;
  }

  // Obtiene una fecha de tipo String de formato YYYY-MM-DD y regresa una fecha de tipo DATE
  public formatStrDateToDate(strDate:string): Date {
    let arrDate:Array<string> = strDate.split('-');
    return new Date(parseInt(arrDate[0]), parseInt(arrDate[1])-1, parseInt(arrDate[2]));
  }

  // Obtiene una fecha de tipo String de formato YYYY-MM-DD y regresa una fecha de tipo DATE
  public formatStrDateToDate2(strDate:string): Date {
    let arrDate:Array<string> = strDate.split('-');
    return new Date(parseInt(arrDate[0]), parseInt(arrDate[1]), parseInt(arrDate[2]));
  }

  public resizeText(text:string, numCaracteres:number) {    
    let textResize: string = (text.toString()).trim();
    let contact:string = textResize.length > numCaracteres ? '...' : '';
    return textResize.substring(0, numCaracteres) + contact;
  }

  public selectUser(userRegister: string|undefined, userUpdate: string | null | undefined):string {

    if (typeof userRegister === 'string' && (userUpdate === null || userUpdate === undefined) ) {
      return userRegister;
    } else if (userUpdate !== null && userUpdate !== undefined) {
      return userUpdate;
    } else {
      return 'ERR';
    }
  }

  public getTypeFile(codeFile:string): string {
    const arrCatgory: Array<CategoryFile> = docClassification;

    let dataFile = arrCatgory.find((element:CategoryFile) => element.code === codeFile);
    if (dataFile === null || dataFile === undefined) {
      return 'No encontrado';
    }

    return dataFile.category;
  }

  public async convertisBase64($event: File) {
    return new Promise((resolve, reject) => {
      var fr = new FileReader();  
      fr.onload = () => {
        resolve(fr.result )
      };
      fr.onerror = reject;
    });    
  }

  public moneyFormat(money:number): string {
    let newFormat: string = '';

    const formatter = new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD',
    });

    newFormat = formatter.format(money);
    return newFormat;
  }

  public goBack(): void {
    window.history.back();
  }

  public onResize(): boolean {
    return window.innerWidth <= 1050
  }

  public innerWidth(): number {
    return window.innerWidth;
  }

  public applyFilter(event: any, type: string, dataSource: MatTableDataSource<any>, isLoading: boolean, ): MatTableDataSource<any> {
    if (!isLoading) {
      let filterValue:string;
      if (type == 'INP') {
        filterValue = (event.target as HTMLInputElement).value;
      }else{
        // this.txtSearch = event;
        filterValue = event;
      }
      dataSource.filter = filterValue.trim().toLowerCase();
      if (dataSource.paginator) {
        dataSource.paginator.firstPage();
      }
    }
    return dataSource;
  }

  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 objectUserLine(): RequestUserNumberLine {
    const requestUserNumberLine: RequestUserNumberLine = {
      USUARIO: this.getUser(),
      NUMERO_LINEA: this.getLineNumber(),
    }

    return requestUserNumberLine;
  }

  public setChipList(typeList: string): string {
    let background: string = '';
    switch( typeList ) {
      case 'Activo':
        background = 'teal_dark_background';
        break;
      case 'Eliminado':
        background = 'red_dark_background';
        break;
      case 'Bajo':
        background = 'green_dark_background';
        break;
      case 'Baja':
        background = 'green_dark_background';
        break;
      case 'Intermedio':
        background = 'amber_dark_background';
        break;
      case 'Media':
        background = 'amber_dark_background';
        break;
      case 'Alto':
        background = 'deep_orange_dark_background';
        break;
      case 'Alta':
        background = 'deep_orange_dark_background';
        break;
      case 'Crítico':
        background = 'pink_dark_background';
        break;
      case 'Crítica':
        background = 'pink_dark_background';
        break;
      case 'Muy alta':
        background = 'pink_dark_background';
        break;
      case 'Pendiente':
        background = 'amber_primary_background';
        break;
      case 'Notificado':
        background = 'deep_orange_primary_background';
        break;
      case 'Rechazado':
        background = 'red_dark_background';
        break;
      case 'Aceptado':
        background = 'teal_dark_background';
        break;
      case 'En espera':
        background = 'gray_dark_background';
        break;
      case 'En proceso':
        background = 'light_blue_primary_background';
        break;
      case 'Terminada':
        background = 'teal_dark_background';
        break;
      case 'Creado':
        background = 'pink_primary_background';
        break;
      case 'Editado':
        background = 'pink_dark_background';
        break;
      case 'En curso':
        background = 'amber_dark_background';
        break;
      case 'Recibido Parcial':
        background = 'cyan_dark_background';
        break;
      case 'Recibido':
        background = 'cyan_dark_background';
        break;
      case 'Facturado':
        background = 'teal_dark_background';
        break;
      case 'Anulado':
        background = 'red_dark_background';
        break;
      case 'Inactivo':
        background = 'red_dark_background';
        break;
      case 'Resuelto':
        background = 'green_dark_background';
        break;
      case 'Devolución':
        background = 'deep_orange_dark_background';
        break;
      case 'Nuevo':
        background = 'teal_dark_background';
        break;
      case 'Modificado':
        background = 'teal_dark_background';
        break;
      case 'Expirado':
        background = 'red_dark_background';
        break;
    }

    return background;
  }

  async fileExists(url: string){
    try{
      let res: any = await lastValueFrom(this._httpClient.get(url).pipe());
      if(res.status == 200){
        return true;
      }else{
        return false;
      }
    }catch(error: any){
      if(error.status == 200){
        return true;
      }else{
        return false;
      }
    }
  }
}

export interface ResponseData {
  error: Boolean,
  msg: string,
  response: any[]
}

export interface ResponseErrorException {
  exception: string;
  file: string;
  line: number;
  message: string;
}

export interface CategoryFile {
  category: string;
  code: string;
}