import { Component, OnInit } from '@angular/core';
import { ChartConfiguration } from 'chart.js';
import { ControlPanelDetails, ControlPanelDetailsResponse, PanelCountersListResponse, PanelElements } from '../../../../interfaces/control-panel.interface';
import { UserResponse, UsersResponse } from '../../../../interfaces/users.interface';
import { ActivatedRoute } from '@angular/router';
import { ResourcesService } from '../../../../services/resources.service';
import { ControlPanelService } from '../../../../services/control-panel.service';
import { EncService } from '../../../../services/enc.service';
import { FunctionsService } from '../../../../services/functions.service';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { MatDialog } from '@angular/material/dialog';
import { SocketService } from '../../../../services/socket.service';
import { CountersActivatorsService } from '../../../../services/counters-activators.service';
import { UsersProfilesService } from '../../../../services/users-profiles.service';
import { lastValueFrom } from 'rxjs';
import { CounterMeasuresListResponse } from '../../../../interfaces/counters-activators.interface';
import { MeasuresHistoryComponent } from '../../../corrective-maintenance/operations-management/corrective-order-form/measures-history/measures-history.component';

export interface CounterChartConfiguration{
  counterID: string;
  counterEquipment: string;
  chartData: ChartConfiguration['data'],
  chartOptions: ChartConfiguration['options'],
  chartType: ChartConfiguration['type'],
  isAssigned: boolean;
}
interface ModuleElement{
  idModule: string;
  idElement: string;
  isAssigned: boolean;
}
@Component({
    selector: 'app-add-elements',
    templateUrl: './add-elements.component.html',
    styleUrl: './add-elements.component.css',
    standalone: false
})
export class AddElementsComponent implements OnInit {
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  indicatorsMenu: number;
  indicatorsModule: string;

  panelDetails: ControlPanelDetails | null;
  countersCharts: CounterChartConfiguration[];
  panelElements: PanelElements[];
  users: UserResponse[];
  usersConnected: UserResponse[];
  systemAdminElements: ModuleElement[];

  constructor(
    private _router: ActivatedRoute,
    private _resourcesService: ResourcesService,
    private _controlPanelService: ControlPanelService,
    private _encService: EncService,
    private _functionsService: FunctionsService,
    private _matIconRegistry: MatIconRegistry,
    private _domSanitizer: DomSanitizer,
    private _dialog: MatDialog,
    private _socketService: SocketService,
    private _countersActivatorsService: CountersActivatorsService,
    private _usersProfilesService: UsersProfilesService,
  ) {
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = '';
    this.indicatorsMenu = 5;
    this.indicatorsModule = 'S002V01M06COAC';

    this.panelDetails = null;
    this.countersCharts = [];
    this.panelElements = [];
    this.users = [];
    this.usersConnected = [];
    this.systemAdminElements = [];
    
    this._matIconRegistry.addSvgIcon(
      'xls',
      this._domSanitizer.bypassSecurityTrustResourceUrl(window.location.origin + "/assets/img/custom_icons/xls.svg")
    );
  }

  ngOnInit(): void {
    this._router.queryParams.subscribe(params => {
      let dataEnc = params['data'];
      if(dataEnc == undefined){
        this._resourcesService.openSnackBar('No se envió ninguna información.');
        this.goBack(1);
      }else{
        this.getPanel(dataEnc);
      }
    });
  }

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

  async getPanel(idPanel: string){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let panelDetails: ControlPanelDetailsResponse = await lastValueFrom(this._controlPanelService.getPanel(idPanel, idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        let idPanelDec = await this._encService.decrypt(panelDetails.response.ID_PANEL);

        panelDetails.response.NOMBRE_PANEL = `${panelDetails.response.NOMBRE_PANEL} (${idPanelDec})`;
        panelDetails.response.FECREG = this._functionsService.orderDate(panelDetails.response.FECREG);

        if(panelDetails.response.FECMOD != null){
          panelDetails.response.FECMOD = this._functionsService.orderDate(panelDetails.response.FECMOD);
        }
        
        let panelIndicators = JSON.parse(panelDetails.response.INDICADORES_RELACIONADOS) as PanelElements[];
        for(const element of panelIndicators){
          element.module = await this._encService.decrypt(element.module);
          element.idElement = await this._encService.decrypt(element.idElement);

          this.panelElements.push(element);
        }

        this.panelDetails = panelDetails.response;
        this.getIndicators();
      }
    }catch(error: any){
      if(error.error == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else{
        this.errorStr = error.error.msg;
      }

      this.hasError = true;
      this.isLoading = false;
    }
  }
  
  async getIndicators(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let counters: PanelCountersListResponse = await lastValueFrom(this._controlPanelService.getCountersList(idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        let countersArr: CounterChartConfiguration[] = [];
        for(const counter of counters.response){
          let idCounterDec = await this._encService.decrypt(counter.ID_CONTADOR);
          counter.ID_CONTADOR = idCounterDec;

          let codeEquipmentDec = await this._encService.decrypt(counter.CODIGO_EQUIPAMIENTO);
          let idEquipmentDec = await this._encService.decrypt(counter.ID_EQUIPAMIENTO);

          let measuresVals: number[] = [];
          let labels: string[] = [];

          for(const measure of counter.LAST_MEASURES){
            measuresVals.push(measure.VALOR);
            labels.push(this._functionsService.getDateTimeHour(measure.HORA_REGISTRO));
          }
          
          let colorR = Math.ceil(Math.random() * 255);
          let colorG = Math.ceil(Math.random() * 255);
          let colorB = Math.ceil(Math.random() * 255);
      
          let dataset = {
            data: measuresVals,
            label: 'Mediciones',
            backgroundColor: `rgba(${colorR},${colorG},${colorB},0.2)`,
            borderColor: `rgba(${colorR},${colorG},${colorB},1)`,
            pointBackgroundColor: `rgba(${colorR},${colorG},${colorB},1)`,
            pointBorderColor: '#fff',
            pointHoverBackgroundColor: '#fff',
            pointHoverBorderColor: `rgba(${colorR},${colorG},${colorB},0.8)`,
            fill: 'origin',
          };

          let counterChartConfig: CounterChartConfiguration = {
            counterID: idCounterDec,
            counterEquipment: `${codeEquipmentDec} - ${counter.TIPO_EQUIPAMIENTO} - ${counter.MODELO_EQUIPAMIENTO} (${idEquipmentDec})`,
            chartData: {
              datasets: [dataset],
              labels: labels
            },
            chartOptions: {
              elements: {
                line: {
                  tension: 0.5
                },
              },
              scales: {
                y: {
                  position: 'left'
                },
              },
              plugins: {
                legend: { display: true },
                annotation: {
                  annotations: [
                    {
                      type:'line',
                      scaleID: 'x',
                      borderColor: 'white',
                      borderWidth: 2,
                      label: {
                        display: true,
                        position: 'center',
                        font: {
                          weight: 'bold',
                        }
                      }
                    }
                  ]
                }
              }
            },
            chartType: 'line',
            isAssigned: false,
          };

          countersArr.push(counterChartConfig);

          //Inicialización del socket por cada contador
          this._socketService.refreshCounterMeasures().subscribe(async (data: any) => {
            let idSocketCounterDec = await this._encService.decrypt(data.idCounter);
            if(idSocketCounterDec == idCounterDec){
              let idUser = localStorage.getItem('idusuario')!;
              let measures: CounterMeasuresListResponse = await lastValueFrom(this._countersActivatorsService.counterConsultMeasures(
                data.idCounter, 'FECREG', 'D',
                10, 0, idUser, 1
              ));

              if(measures.error){
                this._resourcesService.openSnackBar(measures.msg);
              }else{
                let measuresVals: number[] = [];
                let labels: string[] = [];
        
                for(const measure of measures.response){
                  measuresVals.push(measure.VALOR);
                  labels.push(this._functionsService.getDateTimeHour(measure.HORA_REGISTRO));
                }

                let chartFilt = this.countersCharts.filter(chart => chart.counterID == idCounterDec);
                if(chartFilt.length > 0){
                  let backgroundColor = chartFilt[0].chartData.datasets[0].backgroundColor;
                  let borderColor = chartFilt[0].chartData.datasets[0].borderColor;
                  let pointBackgroundColor = chartFilt[0].chartData.datasets[0].borderColor;
                  let pointHoverBorderColor = chartFilt[0].chartData.datasets[0].borderColor!.toString().replace(',1)', ',0.8)');
      
                  let dataset = {
                    data: measuresVals,
                    label: 'Mediciones',
                    backgroundColor: backgroundColor!.toString(),
                    borderColor: borderColor!.toString(),
                    pointBackgroundColor: pointBackgroundColor!.toString(),
                    pointBorderColor: '#fff',
                    pointHoverBackgroundColor: '#fff',
                    pointHoverBorderColor: pointHoverBorderColor,
                    fill: 'origin',
                  };

                  chartFilt[0].chartData = {
                    datasets: [dataset],
                    labels: labels
                  };
                }
              }
            }
          });
        }

        this.countersCharts = countersArr;
        this.getUsers();
      }
    }catch(error: any){
      if(error.error == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else{
        this.errorStr = error.error.msg;
      }

      this.hasError = true;
      this.isLoading = false;
    }
  }

  async getUsers(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let users: UsersResponse = await lastValueFrom(this._usersProfilesService.getUsers(idUser, 1));

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

      if(this.hasError){
        this.isLoading = false;
      }else{
        let idUserDec = await this._encService.decrypt(idUser);
        let usersArr: UserResponse[] = [];

        for(const user of users.response){
          user.IDUSUARIO = await this._encService.decrypt(user.IDUSUARIO);
          if(user.IDUSUARIO != idUserDec){
            usersArr.push(user);
          }
        }

        this.users = usersArr;
        this.initSocketListener();
      }
    }catch(error: any){
      if(error.error == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else if(error.error.msg == undefined){
        this.errorStr = 'Ocurrió un error inesperado.';
      }else{
        this.errorStr = error.error.msg;
      }

      this.hasError = true;
      this.isLoading = false;
    }
  }

  initSocketListener(){
    this._socketService.currentConnections().subscribe(async (connections) => {
      let idUser = localStorage.getItem('idusuario')!;
      let idUserDec = await this._encService.decrypt(idUser);
      let connectionsStr = `${connections}`;
      let connectionsArr = JSON.parse(connectionsStr);

      for(const connection of connectionsArr){
        let connectionArr = connection.split('.');
        let idConnectedUserDec = await this._encService.decrypt(connectionArr[0]);
        if(idConnectedUserDec != idUserDec){
          let userFilt = this.users.filter(user => user.IDUSUARIO == idConnectedUserDec);
          if(userFilt.length > 0){
            let alreadyConnected = this.usersConnected.filter(user => user.IDUSUARIO == idConnectedUserDec);
            if(alreadyConnected.length < 1){
              let colorR = Math.ceil(Math.random() * 255);
              let colorG = Math.ceil(Math.random() * 255);
              let colorB = Math.ceil(Math.random() * 255);

              userFilt[0].COLOR = `rgb(${colorR}, ${colorG}, ${colorB})`;
              this.usersConnected.push(userFilt[0]);
            }
          }
        }
      }
    });

    this._socketService.newConnection().subscribe(async (connections) => {
      let connectionsStr = `${connections}`;
      let connectionsArr = JSON.parse(connectionsStr);

      for(const connection of connectionsArr){
        let connectionArr = connection.split('.');
        let connectionDec = await this._encService.decrypt(connectionArr[0]);
        let userFilt = this.users.filter(user => user.IDUSUARIO == connectionDec);

        if(userFilt.length > 0){
          let alreadyConnected = this.usersConnected.filter(user => user.IDUSUARIO == connectionDec);
          if(alreadyConnected.length < 1){
            let colorR = Math.ceil(Math.random() * 255);
            let colorG = Math.ceil(Math.random() * 255);
            let colorB = Math.ceil(Math.random() * 255);

            userFilt[0].COLOR = `rgb(${colorR}, ${colorG}, ${colorB})`;
            this.usersConnected.push(userFilt[0]);
          }
        }
      }
    });

    this._socketService.disconnection().subscribe(async (connections) => {
      let connectionsStr = `${connections}`;
      let connectionsArr = JSON.parse(connectionsStr);
      let idUser = localStorage.getItem('idusuario')!;
      let idUserDec = await this._encService.decrypt(idUser);
      let connectionsArrDec: string[] = [];

      for(const connection of connectionsArr){
        let connectionArr = connection.split('.');
        let connectionDec = await this._encService.decrypt(connectionArr[0]);

        if(connectionDec != idUserDec){
          connectionsArrDec.push(connectionDec);
        }
      }

      let connectedUsersAux: UserResponse[] = [];
      for(const connected of connectionsArrDec){
        let userFilt = this.users.filter(user => user.IDUSUARIO == connected);
        if(userFilt.length > 0){
          let alreadyConnected = connectedUsersAux.filter(user => user.IDUSUARIO == connected);
          if(alreadyConnected.length < 1){
            connectedUsersAux.push(userFilt[0]);
          }
        }
      }

      this.usersConnected = connectedUsersAux;
    });

    let connectedUsersElement: ModuleElement = {
      idModule: 'S002V01M01ADSI',
      idElement: 'S002V01P01MOCO',
      isAssigned: false
    };
    
    this.systemAdminElements.push(connectedUsersElement);
    this._socketService.getConnections();
    this.isLoading = false;
    
    this.updateAllPanelElements();
  }

  async updateAllPanelElements(){
    //Elementos de contadores y activadores
    for(const chart of this.countersCharts){
      let panelElementFilt = this.panelElements.filter(element => element.idElement == chart.counterID);
      chart.isAssigned = panelElementFilt.length > 0;
    }

    //Elementos de administrador del sistema
    for(const element of this.systemAdminElements){
      let panelElementFilt = this.panelElements.filter(element0 => element0.idElement == element.idElement);
      element.isAssigned = panelElementFilt.length > 0;
    }
  }

  async savePanelElements(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let panelElementsEnc: PanelElements[] = [];
      let formData = new FormData();

      for(const element of this.panelElements){
        element.module = await this._encService.encrypt(element.module);
        element.idElement = await this._encService.encrypt(element.idElement);

        panelElementsEnc.push(element);
      }
      
      formData.append('id_user', idUser);
      formData.append('linea', '1');
      formData.append('id_panel', this.panelDetails!.ID_PANEL);
      formData.append('elements', JSON.stringify(panelElementsEnc));

      await lastValueFrom(this._controlPanelService.updatePanelElements(formData));
      
      this._socketService.controlPanelUpdated(this.panelDetails!.ID_PANEL);
      this._resourcesService.openSnackBar('Los elementos del panel se actualizaron correctamente.');
      this.goBack(1);
    }catch(error: any){
      if(error.error == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
      }else if(error.error.msg == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado.');
      }else{
        this._resourcesService.openSnackBar(error.error.msg);
      }
    }
  }

  changeIndicatorsMenu(index: number, moduleID: string){
    this.indicatorsMenu = index;
    this.indicatorsModule = moduleID;
  }

  async openMeasuresDialog(idCounter: string){
    let idCounterEnc = await this._encService.encrypt(idCounter);
    this._dialog.open(MeasuresHistoryComponent, {
      width: '720px',
      maxWidth: '720px',
      disableClose: true,
      data: {
        idCounter: idCounterEnc,
      }
    })
  }

  async updatePanelElements(idElement: any){
    let elementFilt: PanelElements | null = null;
    for(const element of this.panelElements){
      if(element.module == this.indicatorsModule && element.idElement == idElement){
        elementFilt = element;
      }
    }

    if(elementFilt == null){
      let newElement: PanelElements = {
        module: this.indicatorsModule,
        idElement: idElement
      };

      this.panelElements.push(newElement);
    }else{
      let elementsAux: PanelElements[] = [];
      for(const element of this.panelElements){
        if(!(element.idElement == elementFilt.idElement && element.module == elementFilt.module)){
          elementsAux.push(element);
        }
      }

      this.panelElements = elementsAux;
    }

    this.updateAllPanelElements();
  }
}
