<template>
  <div>
    <label v-if="caption">{{ caption }}</label>
    <div class="report-render">
      <canvas ref="chartCanvas"></canvas>
    </div>
    <small class="form-text text-muted" v-if="description">
      {{ description }}
    </small>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Chart, ChartData } from 'chart.js';
import { RenderDefinition } from './types';
import { PropType } from 'vue/types/umd';

const escapeCsvValue = (val: any): string => {
  if (val === null || val === undefined) return "";
  let value = val.toString();
  if (value.includes(',') || value.includes('"') || value.includes('\n')) {
    value = `"${value.replace(/"/g, '""')}"`;
  }
  return value;
};

export default defineComponent({
  name: 'ReportRender',
  props: {
    caption: {
      type: String,
    },
    description: {
      type: String,
    },
    type: {
      type: String as () => RenderDefinition['type'],
      required: true,
      default: () => (''),
    },
    data: {
      type: Array as () => RenderDefinition['data'],
      required: true,
      default: () => ([]),
    },
    x: {
      type: Object as () => RenderDefinition['x'],
      required: true,
      default: () => ({}),
    },
    y: {
      type: [Array, Object] as PropType<RenderDefinition['y']>,
      required: true,
      default: () => ([]),
    },
    options: {
      type: Object as () => RenderDefinition['options'],
      required: false,
      default: () => ({}),
    },
    plugins: {
      type: Array as () => RenderDefinition['plugins'],
      required: false,
      default: () => ([]),
    },
    shouldExportCSV: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return {
      chart: null as Chart | null,
    };
  },
  mounted() {
    this.renderChart();
  },
  beforeDestroy() {
    if (this.chart) {
      this.chart.destroy();
    }
  },
  watch: {
    shouldExportCSV(newVal, oldVal) {
      if (newVal === true) {
        this.exportToCSV();
      }
    }
  },
  methods: {
    renderChart() {
      const ctx = this.$refs.chartCanvas as HTMLCanvasElement;
      const labels = this.data.map(item => item[this.x.axis.id.toString()]);
      const yAxisArray = Array.isArray(this.y) ? this.y : [this.y];

      const datasets = yAxisArray.map(yAxis => {
        const datasetData = this.data.map(item => Number(item[yAxis.axis.id.toString()]));
        return {
          label: yAxis.axis.name,
          data: datasetData,
          backgroundColor: 'rgba(126, 172, 215, 0.2)',
          borderColor: 'rgba(126, 172, 215, 1)',
          borderWidth: 1,
        };
      });

      const chartData: ChartData = {
        labels: labels,
        datasets: datasets
      };

      this.chart = new Chart(ctx, {
        type: this.type,
        data: chartData,
        options: this.options,
        plugins: this.plugins
      });
    },
    exportToCSV() {
      let csvContent = "data:text/csv;charset=utf-8,";

      const yAxisArray = Array.isArray(this.y) ? this.y : [this.y];

      // Header
      const headers = [
        escapeCsvValue(this.x.axis.name),
        ...yAxisArray.map(yAxis => escapeCsvValue(yAxis.axis.name))
      ];
      csvContent += headers.join(",") + "\r\n";

      // Rows
      this.data.forEach(item => {
        const row = [
        escapeCsvValue(item[this.x.axis.id.toString()]),
          ...yAxisArray.map(yAxis => escapeCsvValue(item[yAxis.axis.id.toString()]))
        ];
        csvContent += row.join(",") + "\r\n";
      });

      // Encode and download
      const encodedUri = encodeURI(csvContent);
      const link = document.createElement("a");
      link.setAttribute("href", encodedUri);
      link.setAttribute("download", "chart-data.csv");
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);

      this.$emit('exported');
    },
  },
});
</script>

<style scoped>
.report-render {
  position: relative;
}
</style>