import { Component, OnInit } from '@angular/core';
import { ChartConfiguration } from 'chart.js';
import { PRTGChannelConfig, PRTGLastReportsListResponse, PRTGReportDetails, PRTGTreeItem } from '../../../interfaces/prtg-report.interface';
import { SocketService } from '../../../services/socket.service';
import { SystemAdminService } from '../../../services/system-admin.service';
import { ResourcesService } from '../../../services/resources.service';
import { EncService } from '../../../services/enc.service';
import { FunctionsService } from '../../../services/functions.service';
import { lastValueFrom } from 'rxjs';

export interface ChannelChartConfiguration{
  chartData: ChartConfiguration['data'],
  chartOptions: ChartConfiguration['options'],
  chartType: ChartConfiguration['type'],
}
@Component({
    selector: 'app-architecture-monitoring',
    templateUrl: './architecture-monitoring.component.html',
    styleUrl: './architecture-monitoring.component.css',
    standalone: false
})
export class ArchitectureMonitoringComponent implements OnInit {
  isLoading: boolean;
  hasError: boolean;
  errorStr: string;
  screenSize: number;

  prtgTree: PRTGTreeItem[];
  prtgChannels: string[];
  prtgChannelsConfig: Map<string, PRTGChannelConfig>;

  constructor(
    private _socketService: SocketService,
    private _systemAdminService: SystemAdminService,
    private _resourcesService: ResourcesService,
    private _encService: EncService,
    private _functionsService: FunctionsService,
  ) { 
    this.isLoading = true;
    this.hasError = false;
    this.errorStr = '';
    this.screenSize = window.innerWidth;

    this.prtgTree = [];
    this.prtgChannels = [];
    this.prtgChannelsConfig = new Map();
  }

  ngOnInit(): void {
    this.getLastPRTGReports();

    this._socketService.prtgInfoUpdated().subscribe(res => {
      let idReport = res['report'];
      if(idReport != null && idReport != undefined && idReport != ''){
        this.getPRTGReports();
      }
    });
  }

  async getLastPRTGReports(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let reports: PRTGLastReportsListResponse = await lastValueFrom(this._systemAdminService.getPRTGLastReports(idUser, 1));

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

      if(!this.hasError){
        await this.updateChannelCharts(reports.response);
      }

      this.isLoading = false;
    }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 updateChannelCharts(data: PRTGReportDetails[]){
    try{
      this.prtgChannels = [];
      this.prtgChannelsConfig = new Map();

      for(const report of data){
        let reportDataDec = await this._encService.decrypt(report.DATOS);
        let reportDataArr: PRTGTreeItem[] = JSON.parse(reportDataDec);

        for(const item of reportDataArr){
          if(!this.prtgChannels.includes(item.channel.id)){
            this.prtgChannels.push(item.channel.id);
          }

          let channelConfig: PRTGChannelConfig;
          if(this.prtgChannelsConfig.has(item.channel.id)){
            channelConfig = this.prtgChannelsConfig.get(item.channel.id)!;

            let backgroundColor = channelConfig.chartConfig!.chartData.datasets[0].backgroundColor;
            let borderColor = channelConfig.chartConfig!.chartData.datasets[0].borderColor;
            let pointBackgroundColor = channelConfig.chartConfig!.chartData.datasets[0].borderColor;
            let pointHoverBorderColor = channelConfig.chartConfig!.chartData.datasets[0].borderColor!.toString().replace(',1)', ',0.8)');
    
            let measuresVals = channelConfig.chartConfig!.chartData.datasets[0].data;
            measuresVals.push(item.last_measurement.display_value);

            let dataset = {
              data: measuresVals,
              label: 'Mediciones',
              backgroundColor: backgroundColor!.toString(),
              borderColor: borderColor!.toString(),
              pointBackgroundColor: pointBackgroundColor!.toString(),
              pointBorderColor: '#fff',
              pointHoverBackgroundColor: '#fff',
              pointHoverBorderColor: pointHoverBorderColor,
              fill: 'origin',
            };
            
            let measureDate = this._functionsService.orderPRTGTimestamp(item.last_measurement.timestamp);
            let labels = channelConfig.chartConfig!.chartData.labels;
            labels?.push(measureDate);
            
            channelConfig.chartConfig!.chartData = {
              datasets: [dataset],
              labels: labels
            };
          }else{
            let orderedDate = this._functionsService.orderPRTGTimestamp(item.last_measurement.timestamp);
            let measuresVals: number[] = [item.last_measurement.display_value];
            let labels: string[] = [orderedDate];

            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',
            };
            
            channelConfig = {
              channel: '',
              name: '',
              route: '',
              state: false,
              currentValue: '',
              minValue: '',
              maxValue: '',
              chartConfig: {
                chartData: {
                  datasets: [dataset],
                  labels: labels
                },
                chartOptions: {
                  elements: {
                    line: {
                      tension: 0.5
                    },
                  },
                  scales: {
                    y: {
                      position: 'left'
                    },
                  },
                  plugins: {
                    legend: { display: true },
                  }
                },
                chartType: 'line',
              }
            };
          }
          
          channelConfig.channel = item.channel.id;
          channelConfig.name = item.channel.name;

          let routeStr = "";
          for(const item0 of item.path){
            routeStr += `/${item0.name} (${item0.id})`;
          }

          channelConfig.route = routeStr;
          this.prtgChannelsConfig.set(item.channel.id, channelConfig);
        }
      }

      data.reverse();

      for(const report of data){
        let reportDataDec = await this._encService.decrypt(report.DATOS);
        let reportDataArr: PRTGTreeItem[] = JSON.parse(reportDataDec);
        
        for(const item of reportDataArr){
          let channelConfig = this.prtgChannelsConfig.get(item.channel.id);

          let min = parseFloat(item.last_measurement.display_minimum.toFixed(2));
          let max = parseFloat(item.last_measurement.display_maximum.toFixed(2));
          let val = parseFloat(item.last_measurement.display_value.toFixed(2));

          channelConfig!.state = val >= min && val <= max;
          channelConfig!.currentValue = `${val} ${item.unit.display_unit}`;
          channelConfig!.minValue = `${min} ${item.unit.display_unit}`;
          channelConfig!.maxValue = `${max} ${item.unit.display_unit}`;
        }
      }
    }catch(error: any){
    }
  }

  async getPRTGReports(){
    try{
      let idUser = localStorage.getItem('idusuario')!;
      let reports: PRTGLastReportsListResponse = await lastValueFrom(this._systemAdminService.getPRTGLastReports(idUser, 1));

      if(reports.error){
        this._resourcesService.openSnackBar(reports.msg);
      }else{
        await this.updateChannelCharts(reports.response);
      }
    }catch(error: any){
      if(error.error == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado (1).');
      }else if(error.error.msg == undefined){
        this._resourcesService.openSnackBar('Ocurrió un error inesperado (2).');
      }else{
        this._resourcesService.openSnackBar(error.error.msg);
      }
    }
  }

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

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