/**
 * DashboardComponent WIDGET
 * 
 * DashboardComponent component widget to show component output data. Will draw the widget accordantly to the DashboardComponent configuration (TABLE or CHART)
 
 * Input's:
 *  - dashboardComponent  : The DashboardComponent instance to draw. If present, dashboardComponentId input will be IGNORED.
 *  - dashboardComponentId: The DashboardComponent id. 
 *
 * Event's:
 *  <NO EVENTS>
 *
 * Usage
 *  - In the intended *.component.html insert the code:
 *    <dashboard-component-widget [dashboardComponent]="_dashboardComponent()"></dashboard-component-widget>
 *    OR
 *    <dashboard-component-widget [dashboardComponentId]="_dashboardComponentId()"></dashboard-component-widget>
 *  - In the *.component.ts insert the code:
 *    import { DashboardComponentWidgetComponent } from 'app/entities/dashboard-component/factory/widgets/dashboard-component-widget.component';
 *    ...
 *    add component imports, @Component({ imports: [ DashboardComponentWidgetComponent ] })
 *    ...
 *    _dashboardComponent= input<IDashboardComponent | null>(null);
 *    OR
 *    _dashboardComponentId= input<long | null>(null);
 */
 
import { ChangeDetectorRef, Component, Output, Input, inject, OnInit, EventEmitter, AfterViewInit, OnChanges, SimpleChanges } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpResponse } from '@angular/common/http';
import { map, tap, filter } from 'rxjs';

// CHART.JS
import { NgChartsModule } from 'ng2-charts';
import { ChartOptions, ChartType, ChartData } from 'chart.js';

import SharedModule from 'app/shared/shared.module';
import { IDashboardComponent } from '../../dashboard-component.model';
import { IDashboardComponentDetailValue } from '../../dashboard-component-detail-value.model';
import { DashboardComponentService } from '../../service/dashboard-component.service';

@Component({
  standalone: true,
  selector: 'dashboard-component-chart',
  templateUrl: './dashboard-component-chart.component.html',
  styleUrl: './dashboard-component-chart.component.css',
  imports: [SharedModule, NgChartsModule, RouterModule]
})
export class DashboardComponentChart implements OnInit, AfterViewInit, OnChanges {
  @Input() dashboardComponent: IDashboardComponent | null = null; // DashboardComponent instance, if the consumer already loaded a DashboardComponent instance.
  @Input() dashboardComponentId: number | null = null;            // DashboardComponent Îd, if the consumer doesn't have an instance
  @Input() periodVersionId: number | null = null;                 // PeriodVersion Id, needed to retrive the Output data for the component

  dashboardComponentDetailValues: Map<string, IDashboardComponentDetailValue[]> = new Map();
  title: string = "";
  
  protected dashboardComponentService = inject(DashboardComponentService);
  
  /* CHART variables */
  public barChartOptions: ChartOptions = {
    responsive: true,
    plugins: {
      title: {
        display: true,
        text: '123 4567 789'
      }
    }
  };
  public barChartLabels: string[] = ['January', 'February', 'March', 'April'];
  public chartType: ChartType = 'bar' as ChartType;
  
  chartData: ChartData<'bar'> = {
    labels: [],
    datasets: [
      { data: [], label: 'Dataset 1', backgroundColor: 'rgba(75,192,192,0.6)' }
    ]
  };
  
  chartOptions: ChartOptions<'bar'> = {
    responsive: true,
    scales: {
      x: {},
      y: { beginAtZero: true }
    }
  };
  
  constructor(private cdRef: ChangeDetectorRef) {}
  
  ngOnInit(): void {
    this.renderChart();
  }
  
  ngAfterViewInit() {
    setTimeout(() => {
      if (this.chartData) {
        this.renderChart();
      }
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes['chartData'] && this.chartData) {
      this.renderChart();
    }
  }
  
  previousState(): void {
    window.history.back();
  }

  private renderChart(): void {
    // If a DashboardComponent was given, just build
    if (this.dashboardComponent) {
      this.dashboardComponentId = this.dashboardComponent?.id;
      this.title = this.dashboardComponent?.name ?? "";
      //TODO : Build
      this.build();
    } else if (this.dashboardComponentId) {
      // Must load the DashboardComponent first, and then build
      this.build();
    } else {
      // Unable to have a DashboardComponent. EXCEPTION
    }
  }

  private build(): void {
    if (this.dashboardComponentId && this.periodVersionId) {
      this.dashboardComponentService
        .loadValuesForComponent(this.dashboardComponentId, this.periodVersionId)
        .pipe(
          map(
            (res: HttpResponse<any>) => {
              const data = res.body ?? {};

              // Check if the data is already a Map or if it's a plain object
              if (data instanceof Map) {
                return data;
              } else {
                // Convert object to Map if it's not. 
                // I had to do it like this, otherwise, it wouldn't be a Map().
                const map = new Map<string, IDashboardComponentDetailValue[]>();
                Object.keys(data).forEach(key => {
                  map.set(key, data[key]);
                });
                return map;
              }
            }
          )
        )
        .subscribe(
          (_dashboardComponentDetailValues: Map<string, IDashboardComponentDetailValue[]>) => {
              this.dashboardComponentDetailValues = _dashboardComponentDetailValues;
              this.buildChart();
          }
        );
    }
  }

  private buildChart(): void {
    this.barChartLabels.length = 0; // Clear the label array
    
    const variableMap: Map<string, number[]> = new Map();
    const variableLabelValues: Map<string, string> = new Map();
    const variableColorValues: Map<string, string> = new Map();
    
    this.dashboardComponentDetailValues.forEach((value, key) => {
      console.log(`Key: ${key}`);
      let isFirst = true;
      
      value.forEach(item => {
        if (isFirst) this.barChartLabels.push(item?.organization?.code || 'undefined');  //Add company label. Get it from the first element.
        isFirst = false;
        
        const variableValues = variableMap.get(item?.dashboardComponentDetail?.variable?.id.toString() || '');
        
        if (variableValues !== undefined) {
          // Append value to array
          variableValues.push(item.value || 0);
        } else {
          // Insert first entry
          variableMap.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', [item.value || 0]);
          variableLabelValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.dashboardComponentDetail?.name || 'undefined');
          variableColorValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.dashboardComponentDetail?.color || '');
        }
      });
    });
    
    //Finally, create data for the chart.
    const myChartData: ChartData<'bar'> = {
      labels: [],
      datasets: [
        { data: [], label: 'Dataset 1', backgroundColor: 'rgba(75,192,192,0.6)' }
      ]
    };
    
    myChartData.labels = this.barChartLabels;
    myChartData.datasets.length = 0;
    
    variableMap.forEach((value, key) => {
      const dataset: { data: number[]; label: string; backgroundColor: string } = { 
        data: value, 
        label: variableLabelValues.get(key) || 'undefined', 
        backgroundColor: variableColorValues.get(key) || '',
      };
      
      myChartData.datasets.push(dataset);
    });
    
    this.chartData = myChartData;
  }
  
  private loadDashboardComponent(_dashboardComponentId: number): void {
    this.dashboardComponent = null;
  }
}
