import { Component, OnInit, ViewChild } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { DetailsFailureEquipment, EquipmentByFailure, ResponseDataGetEquipmentByFailure } from '../../../interfaces/failure-analysis/statistical-analysis';
import { SelectionModel } from '@angular/cdk/collections';
import { FormControl, FormGroup } from '@angular/forms';
import { CatalogFailure, ResponseDataGetCatalogFailure } from '../../../interfaces/failure-analysis/catalog-failure.interface';
import { lastValueFrom, map, Observable, startWith } from 'rxjs';
import { ResourcesService } from '../../../services/resources.service';
import { EncService } from '../../../services/enc.service';
import { FailureAnalysisService } from '../../../services/failure-analysis/failure-analysis.service';
import { Chart, ChartConfiguration, ChartEvent, ChartType } from 'chart.js';
import Annotation from 'chartjs-plugin-annotation';
import { HttpErrorResponse } from '@angular/common/http';
import { BaseChartDirective } from 'ng2-charts';
import * as color from '../../../../../public/assets/json/color_chart.json';

@Component({
    selector: 'app-statistical-analysis',
    templateUrl: './statistical-analysis.component.html',
    styleUrl: './statistical-analysis.component.css',
    standalone: false
})
export class StatisticalAnalysisComponent implements OnInit {
  public dataSource: MatTableDataSource<EquipmentByFailure>;
  public selection = new SelectionModel<EquipmentByFailure>(true, []);
  public displayedColumns: Array<string>;

  public isLoading: boolean;
  public isLoadingEquipment: boolean;

  public formGroup: FormGroup;

  public idFailure:string;

  public arrFailureList: Array<CatalogFailure>;
  public failureListStr: Array<string>;
  public filteredOptionsFailure?: Observable<string[]>;
  
  @ViewChild(BaseChartDirective) chart?: BaseChartDirective;

  public lineChartOptions: ChartConfiguration['options'] = {
    elements: {
      line: {
        tension: 0.5,
      },
    },
    scales: {
      y: {
        position: 'left',
      },
      /* y1: {
        position: 'right',
        grid: {
          color: 'rgba(255,0,0,0.3)',
        },
        ticks: {
          color: 'red',
        },
      }, */
    },
    plugins: {
      legend: { display: true },
      annotation: {
        annotations: [
          /* {
            type: 'line',
            scaleID: 'x',
            value: 'Marzo',
            borderColor: 'orange',
            borderWidth: 2,
            label: {
              display: true,
              position: 'center',
              color: 'orange',
              content: 'Linea Divisoria',
              font: {
                weight: 'bold',
              },
            },
          }, */
        ],
      },
    },
  };
  
  public lineChartData: ChartConfiguration['data'] = {
    datasets: [],
    labels: this.resourcesService.arrMonthLabel,
  };

  public lineChartType: ChartType = 'line';

  constructor( 
    public resourcesService: ResourcesService,
    private _encService: EncService,
    private _failureAnalysisService: FailureAnalysisService,
  ) {
    this.dataSource = new MatTableDataSource<EquipmentByFailure>();
    this.displayedColumns = ['SELECT','CODIGO_EQUIPAMIENTO'];
    this.isLoading = false;
    this.isLoadingEquipment = false;
    this.arrFailureList = [];
    this.failureListStr = [];

    this.idFailure = '';

    this.formGroup = this.createFormGroup();
    Chart.register(Annotation);
  }

  private createFormGroup() {
    const year: number = new Date().getFullYear();
    const startDate: Date = new Date(year, 0, 1);
    const endDate: Date = new Date(year, 11, 31);
    return new FormGroup({
      'FALLA': new FormControl(''),
      'FECHA_INICIO': new FormControl<Date | null>(startDate),
      'FECHA_FIN': new FormControl<Date | null>(endDate),
    });
  }

  async ngOnInit() {
    this.isLoading = true;
    await this.getCatalogFailureActives();
    await this.getEquipmentByFailure();
    this.isLoading = false;

    this.formGroup.controls['FECHA_FIN'].valueChanges.subscribe(async (element) => {
      if (element === null) {
        return;
      }
      let dateFechaInicio: Date = this.formGroup.controls['FECHA_INICIO'].value;
      let dateFechaFin: Date = this.formGroup.controls['FECHA_FIN'].value;
      if ( dateFechaInicio === null || dateFechaInicio === undefined  || dateFechaFin === null || dateFechaFin === undefined ) {
        return;
      }
      this.generateLabelsChart(dateFechaInicio, dateFechaFin);
      await this.generateChart(dateFechaInicio, dateFechaFin);
    });

    this.filteredOptionsFailure = this.formGroup.controls['FALLA'].valueChanges.pipe(
      startWith(''),
      map( value => {
        value = value === null || value === undefined ? '' : value;
        const filterValue = value.toLowerCase();
        return this.failureListStr.filter(item => item.toLowerCase().includes(filterValue));
      })
    );

    this.formGroup.controls['FALLA'].valueChanges.subscribe(async (element) => {
      if ( !element.includes('(') || !element.includes(')') ) {
        return;
      }
      this.idFailure = element.split('(')[1].split(')')[0];
      await this.getEquipmentByFailure();
      
    });

    this.selection.changed.subscribe(async (element) => {
      if (element === null || element === undefined ) {
        return;
      }
      let dateFechaInicio: Date = this.formGroup.controls['FECHA_INICIO'].value;
      let dateFechaFin: Date = this.formGroup.controls['FECHA_FIN'].value;
      if ( dateFechaInicio === null || dateFechaInicio === undefined  || dateFechaFin === null || dateFechaFin === undefined ) {
        return;
      }
      this.generateLabelsChart(dateFechaInicio, dateFechaFin);
      await this.generateChart(dateFechaInicio, dateFechaFin);
    });
  }

  private async getCatalogFailureActives() {
    const user: string = this.resourcesService.getUser();
    const line: number = this.resourcesService.getLineNumber();
    await lastValueFrom(this._failureAnalysisService.getCatalogFailureActives(user, line)).then(
      (responseData: ResponseDataGetCatalogFailure) => {
        if (!responseData.error) {
          this.arrFailureList = responseData.response;
          this.failureListStr = [];
          responseData.response.map((catalogFailure:CatalogFailure, index:number) => {
            if (index === 0) {
              this.idFailure = catalogFailure.ID_FALLA.toString();
              this.formGroup.controls['FALLA'].setValue(`${catalogFailure.NOMBRE_FALLA} (${catalogFailure.ID_FALLA})`);
            }
            this.failureListStr.push(`${catalogFailure.NOMBRE_FALLA} (${catalogFailure.ID_FALLA})`);
          });
        } else {
          this.resourcesService.openSnackBar(`${responseData.msg}`);
        }
      }, async (httpErrorResponse: HttpErrorResponse) => {
        let response = this.resourcesService.checkErrors(httpErrorResponse)
        if (response !== null && response.reload) {
          await this.getCatalogFailureActives();
        }
      }
    );
  }

  private async getEquipmentByFailure() {
    this.isLoadingEquipment = true;
    const encFailure:string = await this._encService.encrypt(this.idFailure);
    const user: string = this.resourcesService.getUser();
    const line: number = this.resourcesService.getLineNumber();
    await lastValueFrom(this._failureAnalysisService.getEquipmentByFailure(encFailure, user, line)).then(
      (responseData: ResponseDataGetEquipmentByFailure) => {
        if (!responseData.error) {
          this.dataSource.data = responseData.response;
        } else {
          this.resourcesService.openSnackBar(`${responseData.msg}`);
        }
      }, async (httpErrorResponse: HttpErrorResponse) => {
        let response = this.resourcesService.checkErrors(httpErrorResponse)
        if (response !== null && response.reload) {
          await this.getEquipmentByFailure();
        }
      }
    );
    this.isLoadingEquipment = false;
  }
  
  private generateLabelsChart( dateFechaInicio: Date, dateFechaFin: Date) {    
    const startYear: number = dateFechaInicio.getFullYear();
    const endYear: number = dateFechaFin.getFullYear();
    const startMonth: number = dateFechaInicio.getMonth();
    const endMonth: number = dateFechaFin.getMonth();
    
    const differenceQuantity: number = (endYear - startYear) + 1;
    
    let coursedYears:number = 1;
    let arrLabels: Array<string> = [];
    let arrYearsLinear: Array<number> = [ startYear ];

    let mountCountInit:number = startMonth;

    let coursedMountTemp: number = startMonth;
    let coursedYearTemp: number = 1;
    
    let finishCicle: boolean = true;
    let yearInitials: number = startYear;

    
    do {
      coursedMountTemp = mountCountInit;
      coursedYearTemp = coursedYears;

      arrLabels.push( `${this.resourcesService.arrMonthLabel[mountCountInit]} - ${yearInitials}`);
      mountCountInit++;

      if (mountCountInit === 12) {
        arrYearsLinear.push(startYear + coursedYears)
        coursedYears++;
        yearInitials++;
        mountCountInit = 0;
      }

      if (differenceQuantity === coursedYearTemp && coursedMountTemp === endMonth) {
        finishCicle = false;
      }
      if (coursedYears === 100) {
        return;
      }

    } while(finishCicle);

    this.lineChartData.labels = arrLabels;
    this.chart?.chart?.update();
  }

  public async generateChart(dateFechaInicio: Date, dateFechaFin: Date) {
    if ( dateFechaInicio === null || dateFechaInicio === undefined || dateFechaFin === null || dateFechaFin === undefined ) {
      this.resourcesService.openSnackBar(`Seleccione un rango de fechas válido.`);
      return; 
    }
    
    let arrEquipmentsListItem: Array<EquipmentByFailure> = this.selection.selected;
    if (arrEquipmentsListItem.length === 0) {
      this.resourcesService.openSnackBar(`Seleccione al menos un equipamiento.`);
      this.lineChartData.datasets = [];
      this.chart?.chart?.update();
      return; 
    }

    this.lineChartData.datasets = [];
    arrEquipmentsListItem.map((equipmentByFailure: EquipmentByFailure, indexList: number) => {

      let mapMonthSelected = new Map<string, number>([]);
      equipmentByFailure.DETALLES.map((detailsFailure: DetailsFailureEquipment ) => {
        const arrDatetime: Array<string> = detailsFailure.FECHA_FALLA.split(' ');
        const arrDate:Array<string> = arrDatetime[0].split('-');

        let year: number = parseInt(arrDate[0]);
        let month: number = parseInt(arrDate[1]) - 1;

        let label: string = `${this.resourcesService.arrMonthLabel[month]} - ${year}`;
        let count = mapMonthSelected.get(label);

        if (count === null || count === undefined) {
          count = 1;
        } else {
          count = count + 1;
        }
        mapMonthSelected.set(label, count);
      });

      const startYear: number = dateFechaInicio.getFullYear();
      const endYear: number = dateFechaFin.getFullYear();
      const startMonth: number = dateFechaInicio.getMonth();
      const endMonth: number = dateFechaFin.getMonth();
      
      const differenceQuantity: number = (endYear - startYear) + 1;
      
      let arrLabels: Array<number> = [];

      let coursedYears:number = 1;
      let arrYearsLinear: Array<number> = [ startYear ];

      let mountCountInit:number = startMonth;

      let coursedMountTemp: number = startMonth;
      let coursedYearTemp: number = 1;
      
      let finishCicle: boolean = true;
      let yearInitials: number = startYear;

      
      do {
        coursedMountTemp = mountCountInit;
        coursedYearTemp = coursedYears;

        let labelItem = `${this.resourcesService.arrMonthLabel[mountCountInit]} - ${yearInitials}`;
        let countFailure = mapMonthSelected.get(labelItem);
        if (countFailure === null || countFailure === undefined) {
          arrLabels.push(0);
        } else {
          arrLabels.push(countFailure);
        }
        
        mountCountInit++;

        if (mountCountInit === 12) {
          arrYearsLinear.push(startYear + coursedYears)
          coursedYears++;
          yearInitials++;
          mountCountInit = 0;
        }

        if (differenceQuantity === coursedYearTemp && coursedMountTemp === endMonth) {
          finishCicle = false;
        }
        if (coursedYears === 100) {
          return;
        }

      } while(finishCicle);

      let arrColorChart = color;
      let countColorChart = arrColorChart.color.length;

      if (indexList >= countColorChart) {
        let difference: number = indexList - countColorChart;
        indexList = difference;
      }
      
      this.lineChartData.datasets.push({
        data: arrLabels,
        label: equipmentByFailure.CODIGO_EQUIPAMIENTO,

        backgroundColor: arrColorChart.color[indexList].backgroundColor,
        borderColor: arrColorChart.color[indexList].borderColor,

        pointBackgroundColor: 'rgba(148,159,177,1)',
        pointBorderColor: '#fff',
        pointHoverBackgroundColor: '#fff',
        pointHoverBorderColor: 'rgba(148,159,177,0.8)',
        fill: 'origin',
      });

    });

    this.chart?.chart?.update();
    
  }

  toggleAllRows() {
    if (this.isAllSelected()) {
      this.selection.clear();
      return;
    }

    this.selection.select(...this.dataSource.data);
  }

  isAllSelected() {
    const numSelected = this.selection.selected.length;
    const numRows = this.dataSource.data.length;
    return numSelected === numRows;
  }

  checkboxLabel(row?: EquipmentByFailure): string {
    if (!row) {
      return `${this.isAllSelected() ? 'deselect' : 'select'} all`;
    }
    return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.CODIGO_EQUIPAMIENTO}`;
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }

  public chartHovered({
    event,
    active,
  }: {
    event?: ChartEvent;
    active?: object[];
  }): void {
    // console.log(event, active);
  }

  public chartClicked({
    event,
    active,
  }: {
    event?: ChartEvent;
    active?: object[];
  }): void {
    // console.log(event, active);
  }
}
