<template>
    <div class="campaign-pie">
        <Pie :chart-data="displayChartData" :chart-options="chartOptions" :plugins="plugins" />
        <ul class="campaign-pie-legend">
            <li
                v-for="item in legendItems"
                :key="item.index"
                class="campaign-pie-legend-item"
                :class="{ 'is-hidden': item.hidden }"
                @click="toggle(item.index)"
            >
                <span class="campaign-pie-legend-dot" :style="{ backgroundColor: item.color }"></span>
                <span class="campaign-pie-legend-label">{{ item.label }} ({{ item.count }})</span>
            </li>
        </ul>
    </div>
</template>

<script>
    import { Pie } from "vue-chartjs/legacy";
    import {
        Chart as ChartJS,
        Title, Tooltip, Legend,
        ArcElement, CategoryScale
    } from "chart.js";

    ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);

    /**
     * Plugin inline (sans dependance) : ecrit le pourcentage sur chaque quartier
     * et le total au centre de l'anneau.
     */
    const percentLabels = {
        id: "percentLabels",
        afterDatasetsDraw: function (chart) {
            const ctx = chart.ctx;
            chart.data.datasets.forEach(function (dataset, datasetIndex) {
                const meta = chart.getDatasetMeta(datasetIndex);
                if (meta.hidden) {
                    return;
                }
                const total = dataset.data.reduce(function (sum, v) {
                    return sum + (v || 0);
                }, 0);
                if (!total) {
                    return;
                }
                meta.data.forEach(function (arc, i) {
                    const value = dataset.data[i] || 0;
                    const percent = Math.round((value / total) * 100);
                    if (percent < 4) {
                        return;
                    }
                    const pos = arc.tooltipPosition();
                    const text = percent + "%";
                    ctx.save();
                    ctx.font = "bold 12px sans-serif";
                    ctx.textAlign = "center";
                    ctx.textBaseline = "middle";
                    // Contour sombre + texte blanc : lisible sur toute couleur.
                    ctx.lineWidth = 3;
                    ctx.strokeStyle = "rgba(0, 0, 0, 0.45)";
                    ctx.strokeText(text, pos.x, pos.y);
                    ctx.fillStyle = "#fff";
                    ctx.fillText(text, pos.x, pos.y);
                    ctx.restore();
                });
            });

            // Total au centre de l'anneau (premier dataset).
            const firstMeta = chart.getDatasetMeta(0);
            const firstData = chart.data.datasets[0];
            if (!firstData || (firstMeta && firstMeta.hidden) || !chart.chartArea) {
                return;
            }
            const grandTotal = firstData.data.reduce(function (sum, v) {
                return sum + (v || 0);
            }, 0);
            const cx = (chart.chartArea.left + chart.chartArea.right) / 2;
            const cy = (chart.chartArea.top + chart.chartArea.bottom) / 2;
            ctx.save();
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillStyle = "#111827";
            ctx.font = "bold 20px sans-serif";
            ctx.fillText(String(grandTotal), cx, cy);
            ctx.restore();
        }
    };

    export default {
        name: "PieChart",

        components: { Pie },

        props: {
            /** Donnees au format Chart.js : { labels, datasets }. */
            chartData:    { type: Object, required: true },
            /** Options Chart.js passees par le parent. */
            chartOptions: { type: Object, default: () => ({}) }
        },

        data: function () {
            return {
                plugins: [percentLabels],
                // Index des parts masquees (clic sur la legende).
                hidden: {}
            };
        },

        computed: {
            /**
             * Entrees de la legende HTML : libelle, compte, couleur, index et
             * etat masque. Construites a partir de TOUTES les donnees (les
             * masquees restent dans la legende, barrees).
             *
             * @returns {Array<object>}
             */
            legendItems: function () {
                var labels = this.chartData.labels || [];
                var dataset = (this.chartData.datasets && this.chartData.datasets[0]) || {};
                var data = dataset.data || [];
                var colors = dataset.backgroundColor || [];
                var hidden = this.hidden;
                return labels.map(function (label, i) {
                    return {
                        index: i,
                        label: label,
                        count: data[i] != null ? data[i] : 0,
                        color: Array.isArray(colors) ? colors[i % colors.length] : colors,
                        hidden: !!hidden[i]
                    };
                });
            },

            /**
             * Donnees reellement tracees : les parts masquees sont retirees, ce
             * qui recalcule automatiquement les pourcentages et le total.
             *
             * @returns {{ labels: Array, datasets: Array }}
             */
            displayChartData: function () {
                var labels = this.chartData.labels || [];
                var dataset = (this.chartData.datasets && this.chartData.datasets[0]) || {};
                var data = dataset.data || [];
                var colors = dataset.backgroundColor || [];
                var hidden = this.hidden;
                var keptLabels = [];
                var keptData = [];
                var keptColors = [];
                labels.forEach(function (label, i) {
                    if (!hidden[i]) {
                        keptLabels.push(label);
                        keptData.push(data[i]);
                        keptColors.push(Array.isArray(colors) ? colors[i % colors.length] : colors);
                    }
                });
                return {
                    labels: keptLabels,
                    datasets: [Object.assign({}, dataset, {
                        data: keptData,
                        backgroundColor: keptColors
                    })]
                };
            }
        },

        methods: {
            /**
             * Masque / reaffiche une part au clic sur la legende.
             *
             * @param {number} index Index de la part
             * @returns {void}
             */
            toggle: function (index) {
                this.$set(this.hidden, index, !this.hidden[index]);
            }
        }
    };
</script>
