/*
 * Copyright (C) 2020 Robert Bosch GmbH Copyright (C) 2020 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';

import { BciChartData, BciChartType } from './chartjs.models';
import { Chart, ChartOptions } from 'chart.js';
import {createBarChart, createLineChart, registerChartBasics, registerChartType} from './chartjs-helper-functions';

@Component({
  selector: 'bci-chartjs-chart',
  templateUrl: './chartjs-chart.html',
  styleUrls: ['./chartjs-chart.component.scss']
})
export class ChartjsChartComponent implements OnInit, OnChanges {
  @Input() type: BciChartType;
  @Input() data: BciChartData;
  @Input() options: ChartOptions;

  @ViewChild('chartContainer', { static: true })
  chartContainer: ElementRef;
  private chart: Chart;
  private registeredChartTypes = new Set();

  ngOnInit(): void {
    registerChartBasics();
    if (!this.chart && this.type) {
      switch (this.type) {
        case 'bar':
          this.chart = createBarChart(this.chartContainer);
          break;
        case 'line':
          this.chart = createLineChart(this.chartContainer);
          break;
        default:
          console.error('unfortunately bci-chartjs-chart does not support chartjs type ' + this.type);
      }
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (!this.type || !this.chart) {
      setTimeout(() => {
        this.ngOnChanges(changes);
      }, 100);
      return;
    }

    let dirty = false;
    const dataChange = changes['data'];
    if (dataChange && dataChange.previousValue !== dataChange.currentValue) {
      this.handleDataChange(dataChange);
      dirty = true;
    }

    const optionsChange = changes['options'];
    if (optionsChange && optionsChange.previousValue !== optionsChange.currentValue) {
      Object.entries(optionsChange.currentValue).forEach(([key, value]) => {
        if (key === 'plugins') {
          Object.entries(value).forEach(([pluginKey, pluginValue]) => {
            this.chart.options.plugins[pluginKey] = pluginValue;
          });
        } else {
          this.chart.options[key] = value;
        }
      });
      dirty = true;
    }

    if (dirty) {
      this.chart.update();
    }
  }

  handleDataChange(dataChange: any) {
    const oldDatasetMetas = this.chart.data?.datasets?.map((_, index) => this.chart.getDatasetMeta(index)) ?? [];
    this.chart.data = dataChange.currentValue;
    this.chart.data?.datasets?.forEach((dataSet, index) => {
      // keep visibility of datasets across data update
      const oldMeta = oldDatasetMetas[index];
      if (oldMeta?.label === dataSet.label && oldMeta.hidden) {
        this.chart.setDatasetVisibility(index, false);
      }

      if (dataSet.type && !this.registeredChartTypes.has(dataSet.type)) {
        registerChartType(dataSet.type);
        this.registeredChartTypes.add(dataSet.type);
      }
    });
  }
}
