import { DOCUMENT } from '@angular/common';
import { SystemAdminService } from './../../../../services/system-admin.service';
import { TempFileInfo } from './../../../system-admin/advices/new-advice/new-advice.component';
import { TimePickerComponent } from './../../../resources/dialogs/time-picker/time-picker.component';
import { MatDialog } from '@angular/material/dialog';
import { MatTableDataSource } from '@angular/material/table';
import { ErrorStateMatcher } from '@angular/material/core';
import { FormGroup, FormControl, Validators, FormGroupDirective, NgForm } from '@angular/forms';
import { EncService } from './../../../../services/enc/enc.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute } from '@angular/router';
import { Component, OnInit, ViewChild, ElementRef, Inject } from '@angular/core';
import { availableFiles } from 'src/environments/environment.prod';
import { lastValueFrom } from 'rxjs';

interface EquipmentInfo{
  CODIGO: string;
  DENOMI: string;
  FAMILI: string;
  SUBFAM: string;
  ESTADO: string;
}
const EQUIPMENT_TMP: EquipmentInfo[] = [
  {
    CODIGO: '01.110.P01-15001.CAM_TCG.CTV.I.HICDE-X3G21-000001',
    DENOMI: 'Hickvision Cámara IP DOMO IR para Exteriores',
    FAMILI: 'Sistema de Telecomunicaciones',
    SUBFAM: 'Videovigilante',
    ESTADO: 'Instalado'
  },
  {
    CODIGO: '01.502.P01-09001.DIS_TN.FRN.I.PAFRE-XXOEM-000001',
    DENOMI: 'Pastillas de Freno',
    FAMILI: 'Tren Nuevo',
    SUBFAM: 'Sistema de Frenos',
    ESTADO: 'Instalado'
  },
  {
    CODIGO: '01.PCC.P01-13001.R42.B4-01_TC.RMS.I.ENCIS-NCC500-000002',
    DENOMI: 'Enrutador CISCO',
    FAMILI: 'Telecomunicaciones',
    SUBFAM: 'Red Multiservicios',
    ESTADO: 'Instalado'
  },
  {
    CODIGO: '01.PCC.P01-13001.R42.H7-06_TC.RMS.I.PAPCI-XXX96F-000001',
    DENOMI: 'Patch Panel Cisco',
    FAMILI: 'Telecomunicaciones',
    SUBFAM: 'Red Multiservicios',
    ESTADO: 'Instalado'
  },
  {
    CODIGO: '01.302.P01-14002.DVR.10,02:315.P01.14002-DVR.16,02_TCG.CTV.T.HICTU-HIM1-000020',
    DENOMI: 'Hickivision DVR de 16 Canales Turbo HD',
    FAMILI: 'Sistema de Telecomunicaciones',
    SUBFAM: 'Videovigilancia',
    ESTADO: 'Traslado'
  },
  {
    CODIGO: '01.110.S01-14001.UDF.17,08:160.UDF.S01-14001.18,08_V1.014.I.CALIG-XGB6KG-000100',
    DENOMI: 'Carril Ligero',
    FAMILI: 'Sistema de Vías',
    SUBFAM: 'Distribución de Durmientes',
    ESTADO: 'Instalado'
  },
  {
    CODIGO: '01.160.S01-03010.VEN.00010:110.P02-03010.VEN.00020_MEP.ACC.I.DUVEN-XXTDC-000002',
    DENOMI: 'Cable de Red',
    FAMILI: 'Telecomunicaciones',
    SUBFAM: 'Red Multiservicios',
    ESTADO: 'Instalado'
  }
];
interface Specialty{
  ID: string;
  NAME: string;
}
const SPECIALTIES: Specialty[] = [
  {ID: 'S1', NAME: 'Mecánica'},
  {ID: 'S2', NAME: 'Electricidad'},
  {ID: 'S3', NAME: 'Electrónica'},
  {ID: 'S4', NAME: 'Control'},
  {ID: 'S5', NAME: 'Neumática'},
  {ID: 'S6', NAME: 'Ingeniería Civil'},
  {ID: 'S7', NAME: 'Sistemas'},
];
interface TeamInfo{
  ID: string;
  NOMB: string;
}
@Component({
  selector: 'app-new-work-order',
  templateUrl: './new-work-order.component.html',
  styleUrls: ['./new-work-order.component.css']
})
export class NewWorkOrderComponent implements OnInit {
  public btnSmall: boolean = false;
  minDate: Date;
  verticalAttach: boolean = false;
  attached: TempFileInfo[];

  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  action: string;
  isNew: boolean;
  idOrder: string;
  cols: number;
  orderType: string;
  isUploading: boolean;

  formGroup = new FormGroup({
    //Parte 1
    fecIni: new FormControl({ value: '', disabled: true }, Validators.required),
    horIni: new FormControl({ value: '', disabled: true }, Validators.required),
    inmTime: new FormControl({ value: '', disabled: true }, [Validators.required, Validators.pattern('[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)')]),
    frequency: new FormControl({ value: '', disabled: true }, [Validators.required, Validators.pattern('^[0-9]*$')]),
    //Parte 2
    period: new FormControl({ value: '', disabled: true }, [Validators.required]),
    idOrder: new FormControl(''),
    description: new FormControl('', [Validators.required, Validators.maxLength(100)]),
    clasification: new FormControl('', [Validators.required, Validators.maxLength(50)]),
    priority: new FormControl('', [Validators.required]),
    equipment: new FormControl('', [Validators.required]),
    //Parte 3
    analisis: new FormControl('', [Validators.required, Validators.minLength(20)]), 
    specialties: new FormControl('', Validators.required),
  });

  matcher = new WorkOrderStateMatcher();
  equipments: EquipmentInfo[] = [];
  specialties: Specialty[] = [];
  specialtiesSelected: Map<string, string>;

  dataSource: MatTableDataSource<any>;
  displayedColumns: string[] =  ['CODIGO', 'DENOMI', 'FAMILI', 'SUBFAM', 'ESTADO', 'ACCIONES'];
  specialtiesDataSource: MatTableDataSource<Specialty>;
  specialtiesDisplayedColumns: string[] = ['ESPECIALIDAD', 'TIPO', 'PERSONAL'];

  @ViewChild('file') uploader?: ElementRef;

  constructor(
    private _activatedRoute: ActivatedRoute,
    private _snackBar: MatSnackBar,
    private _encService: EncService,
    private _dialog: MatDialog,
    private _systemAdminService: SystemAdminService,
    @Inject(DOCUMENT) private _document: Document,
  ) { 
    this.btnSmall = window.innerWidth <= 1405;
    this.verticalAttach = window.innerWidth <= 920;
    this.isLoading = false;
    this.hasError = false;
    this.errorStr = "";
    this.action = "";
    this.isNew = true;
    this.idOrder = "";
    this.cols = this.calcCols();

    this.equipments = EQUIPMENT_TMP;
    this.specialties = SPECIALTIES
    this.dataSource = new MatTableDataSource<any>;
    this.specialtiesDataSource = new MatTableDataSource<Specialty>;

    this.minDate = new Date();
    this.orderType = '';
    this.attached = [];
    this.isUploading = false;
    this.specialtiesSelected = new Map<string, string>();
  }

  ngOnInit(): void {
    this._activatedRoute.queryParams.subscribe(info => {
      let data = info['data'];
      if(data == undefined || data == null || data == ""){
        this.isNew = true;
        this.action = 'Registrar';
        
      }else{
        this.mapData(data);
      }
    });
  }

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

  async mapData(data: string){
    let dataStr = await this._encService.desencriptar(data);
    let dataObj = JSON.parse(dataStr);

    this.action = dataObj.type == 'new' ? 'Registrar' : 'Editar';
    this.isNew = dataObj.type == 'new';
    if(!this.isNew){
      this.idOrder = dataObj.idOrder;
    }
  }

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

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

  calcCols(): number{
    let screenWidth = window.innerWidth;
    if(screenWidth > 1480){
      return 3;
    }else if(screenWidth <= 1480 && screenWidth > 920){
      return 2;
    }else{
      return 1;
    }
  }

  controlErrorStr(controlName: string): string{
    switch(controlName){
      case 'fecIni':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido.';
      break;
      case 'horIni':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido.';
      break;
      case 'inmTime':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido.';
        if(this.formGroup.get(controlName)?.hasError('pattern')) return 'El valor ingresado debe contener únicamente números.';
      break;
      case 'description': 
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
        if(this.formGroup.get(controlName)?.hasError('maxlength')) return 'La longitud máxima del campo es de 100 caracteres.';
      break;
      case 'clasification':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
        if(this.formGroup.get(controlName)?.hasError('maxlength')) return 'La longitud máxima del campo es de 50 caracteres.';
      break;
      case 'priority':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
      break;
      case 'frequency':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
        if(this.formGroup.get(controlName)?.hasError('pattern')) return 'El valor ingresado debe contener únicamente números.';
      break;
      case 'period':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
      break;
      case 'equipment':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
      break;
      case 'analisis':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
        if(this.formGroup.get(controlName)?.hasError('minlength')) return 'La longitud mínima del campo es de 20 caracteres.';
      break;
      case 'observations':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
      break;
      case 'specialties':
        if(this.formGroup.get(controlName)?.hasError('required')) return 'Este campo es requerido';
      break;
    }
    return "";
  }

  updateTable(equipment: string){
    let eq = this.equipments.filter(item => item.CODIGO == equipment);
    this.dataSource = new MatTableDataSource(eq);
  }

  openTimePicker(){
    let dialogRef = this._dialog.open(TimePickerComponent);

    dialogRef.afterClosed().subscribe(res => {
      if(res != null && res != undefined && res != ""){
        this.formGroup.controls.horIni.setValue(res);
      }
    });
  }

  verifyNumbers(){
    if(this.formGroup.controls.inmTime.hasError('pattern')){
      let value = this.formGroup.controls.inmTime.value;
      let newValue = value?.substring(0, value.length - 1);
      this.formGroup.controls.inmTime.setValue(newValue!);
    }
  }

  changeOrderType(type: string){
    if(type == 'unica'){
      this.formGroup.get('fecIni')?.enable();
      this.formGroup.get('fecIni')?.addValidators(Validators.required);
      
      this.formGroup.get('horIni')?.enable();
      this.formGroup.get('horIni')?.addValidators(Validators.required);
      
      this.formGroup.get('inmTime')?.enable();
      this.formGroup.get('inmTime')?.addValidators([Validators.required, Validators.pattern('[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)')]);
      
      this.formGroup.get('frequency')?.disable();
      this.formGroup.get('frequency')?.clearValidators();
      
      this.formGroup.get('period')?.disable();
      this.formGroup.get('period')?.clearValidators();
      
      this.orderType = type;
    }else{
      this.formGroup.get('fecIni')?.disable();
      this.formGroup.get('fecIni')?.clearValidators();
      
      this.formGroup.get('horIni')?.disable();
      this.formGroup.get('horIni')?.clearValidators();
      
      this.formGroup.get('inmTime')?.disable();
      this.formGroup.get('inmTime')?.clearValidators();
      
      this.formGroup.get('frequency')?.enable();
      this.formGroup.get('frequency')?.addValidators([Validators.required, Validators.pattern('^[0-9]*$')]);
      
      this.formGroup.get('period')?.enable();
      this.formGroup.get('period')?.addValidators([Validators.required]);

      this.orderType = type;
    }
  }

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

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

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

  openFileUploader(){
    if(this.attached.length < 3){
      this.uploader?.nativeElement.click();
    }
  }

  updateSpecialtiesTable(value: string[]){
    let specTmp: Specialty[] = [];
    this.specialtiesSelected.clear();

    value.forEach(item => {
      let spec = this.specialties.filter(item2 => item2.ID == item)[0];
      specTmp.push(spec);
      this.specialtiesSelected.set(`${item}`, '');
    });

    this.specialtiesDataSource = new MatTableDataSource(specTmp);
  }

  changeControl(id: string, value: string){
    let typeControl = this._document.getElementById(`type-${id}`) as HTMLInputElement;

    typeControl.value = value;
    this.specialtiesSelected.set(id, value);
  }

  async saveOrder(){
    try{
      if(this.formGroup.invalid){
        this.openSnackBar('Antes de registrar la orden debes completar los campos obligatorios.');
        this.formGroup.markAllAsTouched();
      }else{
        let formData = new FormData();
        let input = this.formGroup.getRawValue();
        let idUser = localStorage.getItem('idusuario');

        formData.append('id_user', idUser!);
        formData.append('linea', '1');
        formData.append('order_type', this.orderType);

        if(this.orderType == 'unica'){
          let dateObj = new Date(input.fecIni!);
          let dateStr = dateObj.toISOString();
          let dateArr = dateStr.split('T');

          formData.append('start_date', dateArr[0]);
          formData.append('start_time', input.horIni!);
          formData.append('inmov_time', input.inmTime!);
        }

        formData.append('description', input.description!);
        formData.append('clasification', input.clasification!);
        formData.append('priority', input.priority!);
        formData.append('equipment', input.equipment!);
        formData.append('analisis', input.analisis!);

        if(this.attached.length > 0){
          let attachedStr = JSON.stringify(this.attached);
          formData.append('attached', attachedStr);
        }

        let specialtiesStr = JSON.stringify(input.specialties);
        let specialtiesArr: string[] = JSON.parse(specialtiesStr);
        
        let isCompleted = true;
        specialtiesArr.forEach(element => {
          let typeControl = this._document.getElementById(`type-${element}`) as HTMLInputElement;
          let typeVal = typeControl.value;

          if(typeVal == 'personal'){
            let persControl = this._document.getElementById(`pers-${element}`) as HTMLInputElement;
            console.log(persControl.value);
          }else if(typeVal == 'equipo'){
            let equiControl = this._document.getElementById(`equi-${element}`) as HTMLInputElement;
            console.log(equiControl.value);
          }else{
            let specialty = this.specialties.filter(item => item.ID == element)[0];
            this.openSnackBar(`No se ha seleccionado ningún tipo para la especialidad '${specialty.NAME}'`);
            isCompleted = false;
          }
        });

        if(isCompleted){
          console.log(formData);
        }
      }
    }catch(error: any){
      if(error.error == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else if(error.error.msg == undefined){
        this.openSnackBar('Ocurrió un error inesperado.');
      }else{
        this.openSnackBar(error.error.msg);
      }
    }
  }
}

export class WorkOrderStateMatcher implements ErrorStateMatcher{
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}