<template>
  <div class="stats-container" :class="containerClass">
    <h2>
      {{ title() }}
      <b-icon :id="chartSettingsID()" icon="gear-fill"></b-icon>
    </h2>
    <div class="chart-container">
      <canvas :id="chartID()"></canvas>
    </div>
    <b-popover
      :target="chartSettingsID()"
      triggers="click"
      :show.sync="settingsShow"
      placement="auto"
      container="stats-container"
      ref="popover"
      @show="onShow"
    >
      <template #title>
        <b-button @click="onClose" class="close" aria-label="Close">
          <span class="d-inline-block" aria-hidden="true">&times;</span>
        </b-button>
        Settings
      </template>

      <div>
        <b-form-group
          label="Limit"
          label-for="limitinput"
          label-cols="3"
          class="mb-1"
          description="Limit number of items"
          invalid-feedback="This field is required"
        >
          <b-form-input
            ref="limitinput"
            id="limitinput"
            v-model="limitState"
            type="number"
            size="sm"
          ></b-form-input>
        </b-form-group>

        <b-button @click="onClose" size="sm" variant="danger">Cancel</b-button>
        <b-button @click="onOk" size="sm" variant="primary">Ok</b-button>
      </div>
    </b-popover>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { StatResult } from '@/apiary/apiary';
import axios from 'axios';
import { Chart, ArcElement, Legend, DoughnutController, Title } from 'chart.js';
import randomColor from 'randomcolor';

export type StatType = 'username' | 'password' | 'ip' | 'country' | 'total';

Chart.register(ArcElement, Legend, DoughnutController, Title);

@Component
export default class StatsPie extends Vue {
  @Prop() private statType!: StatType;

  limit: number;

  limitState: number;

  settingsShow = false;

  stats: StatResult[];

  chart?: Chart;

  constructor() {
    super();
    this.stats = [];
    this.limit = 10;
    this.limitState = 10;
  }

  title(): string {
    switch (this.statType) {
      case 'password':
        return `Top ${this.limit} Passwords`;
      case 'username':
        return `Top ${this.limit} Usernames`;
      case 'ip':
        return `Top ${this.limit} IPs`;
      case 'country':
        return `Top ${this.limit} Countries`;
      case 'total':
        return 'Totals';
      // Why doesn't eslint know that this switch is exhaustive?
      default:
        return 'Top 10 Passwords';
    }
  }

  containerClass(): string {
    return `stats-container-${this.statType}`;
  }

  chartID(): string {
    return `chart-${this.statType}`;
  }

  chartSettingsID(): string {
    return `chartsettings-${this.statType}`;
  }

  settingsID(): string {
    return `settings-${this.statType}`;
  }

  onClose(): void {
    this.settingsShow = false;
  }

  onOk(): void {
    if (this.limitState) {
      this.limit = this.limitState;
      this.settingsShow = false;
    }
  }

  onShow(): void {
    // This is called just before the popover is shown
    // Reset our popover form variables
    this.limitState = this.limit;
  }

  @Watch('limit')
  limitChanged(value: number, oldValue: number): void {
    this.fetchData();
  }

  fetchData(): void {
    const url = `/api/stats?type=${this.statType}&limit=${this.limit}`;
    axios.get<StatResult[]>(url).then((resp) => {
      this.stats = resp.data;
      this.renderPie();
    });
  }

  mounted(): void {
    this.fetchData();
  }

  renderPie(): void {
    const elem = document.getElementById(this.chartID()) as HTMLCanvasElement;
    const ctx = elem.getContext('2d') as CanvasRenderingContext2D;
    const sortedStats = this.stats.sort();
    const values = sortedStats.map((s) => s.count);
    const headers = sortedStats.map((s) => s.name);
    const colors = sortedStats.map(() => randomColor());

    if (this.chart) {
      this.chart.destroy();
    }
    this.chart = new Chart(ctx, {
      type: 'doughnut',
      data: {
        labels: headers,
        datasets: [
          {
            data: values,
            backgroundColor: colors,
          },
        ],
      },
    });
  }
}
</script>

<style lang="scss" scoped>
canvas {
  width: 70vmin;
}
.stats-container {
  align-content: center;
}
</style>
