/* global Chart */
import Component from '@ember/component';
import moment from 'moment';
import {action, computed, get} from '@ember/object';
import {getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

const DATE_FORMAT = 'D MMM YYYY';

export default Component.extend({
    ajax: service(),
    membersStats: service(),

    // public attrs
    nightShift: false,
    lineColor: '#14b8ff',

    stats: null,
    tagName: '',
    chartStats: null,
    chartData: null,
    chartOptions: null,
    showSummary: true,
    showRange: true,
    chartType: '',
    chartSize: '',
    chartHeading: 'Total members',

    isSmall: computed('chartSize', function () {
        if (this.chartSize === 'small') {
            return true;
        }
        return false;
    }),

    startDateLabel: computed('membersStats.stats', function () {
        if (!this.membersStats?.stats?.total_on_date) {
            return '';
        }

        let firstDate = Object.keys(this.membersStats.stats.total_on_date)[0];
        return moment(firstDate).format(DATE_FORMAT);
    }),

    selectedRange: computed('membersStats.days', function () {
        const availableRanges = this.availableRanges;
        return availableRanges.findBy('days', this.membersStats.days);
    }),

    availableRanges: computed(function () {
        return [{
            name: '30 days',
            days: '30'
        }, {
            name: '90 days',
            days: '90'
        }, {
            name: '365 days',
            days: '365'
        }, {
            name: 'All time',
            days: 'all-time'
        }];
    }),

    // Lifecycle ---------------------------------------------------------------

    init() {
        this._super(...arguments);
        this.setChartJSDefaults();
    },

    didReceiveAttrs() {
        this._super(...arguments);

        if (this.chartStats) {
            const {options, data, title, stats} = this.chartStats;

            this.set('stats', stats);
            this.set('chartHeading', title);
            this.setChartData(data);
            this.setChartOptions(options);
        }

        if (this._lastNightShift !== undefined && this.nightShift !== this._lastNightShift) {
            const {options = {}} = this.chartStats;

            this.setChartOptions(options);
        }
        this._lastNightShift = this.nightShift;
    },

    // Actions -----------------------------------------------------------------

    changeDateRange: action(function (range) {
        this.membersStats.days = get(range, 'days');
        this.fetchStatsTask.perform();
    }),

    // Tasks -------------------------------------------------------------------

    fetchStatsTask: task(function* () {
        let stats;
        if (!this.chartType) {
            this.set('stats', null);
            stats = yield this.membersStats.fetch();
            this.setOriginalChartData(stats);
        }
    }),

    setOriginalChartData(stats) {
        if (stats) {
            this.set('stats', stats);

            this.setChartOptions({
                rangeInDays: Object.keys(stats.total_on_date).length
            });

            this.setChartData({
                dateLabels: Object.keys(stats.total_on_date),
                dateValues: Object.values(stats.total_on_date)
            });
        }
    },

    // Internal ----------------------------------------------------------------

    setChartData({dateLabels, dateValues, label = 'Total Members'}) {
        let backgroundColors = this.lineColor;

        if (this.chartType === 'open-rate') {
            backgroundColors = dateLabels.map((val) => {
                if (val) {
                    return this.lineColor;
                } else {
                    return (this.nightShift ? '#7C8B9A' : '#CED4D9');
                }
            });
        }

        this.set('chartData', {
            labels: dateLabels,
            datasets: [{
                label: label,
                cubicInterpolationMode: 'monotone',
                data: dateValues,
                fill: false,
                backgroundColor: backgroundColors,
                pointRadius: 0,
                pointHitRadius: 10,
                borderColor: this.lineColor,
                borderJoinStyle: 'miter',
                maxBarThickness: 20,
                minBarLength: 2
            }]
        });
    },

    setChartOptions({rangeInDays}) {
        let maxTicksAllowed = this.isSmall ? 3 : this.getTicksForRange(rangeInDays);

        if (this.chartType === 'open-rate') {
            maxTicksAllowed = 0;
        }

        this.setChartJSDefaults();
        let options = {
            responsive: true,
            responsiveAnimationDuration: 5,
            maintainAspectRatio: false,
            layout: {
                padding: {
                    top: (this.isSmall ? 20 : 5), // Needed otherwise the top dot is cut
                    right: 10,
                    bottom: (this.isSmall ? 20 : 5),
                    left: 10
                }
            },
            title: {
                display: false
            },
            tooltips: {
                intersect: false,
                mode: 'index',
                displayColors: false,
                backgroundColor: '#15171A',
                xPadding: 7,
                yPadding: 7,
                cornerRadius: 5,
                caretSize: 7,
                caretPadding: 5,
                bodyFontSize: 12.5,
                titleFontSize: 12,
                titleFontStyle: 'normal',
                titleFontColor: 'rgba(255, 255, 255, 0.7)',
                titleMarginBottom: 3,
                filter: (tooltipItems, data) => {
                    if (this.chartType === 'open-rate') {
                        let label = data.labels[tooltipItems.index];
                        if (label === '') {
                            return false;
                        }
                    }
                    return true;
                },
                callbacks: {
                    label: (tooltipItems, data) => {
                        const labelText = data.datasets[tooltipItems.datasetIndex].label;
                        let valueText = data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                        if (this.chartType === 'mrr') {
                            const currency = getSymbol(this.stats.currency);
                            valueText = `${currency}${valueText}`;
                        }
                        if (this.chartType === 'open-rate') {
                            valueText = `${valueText}%`;
                        }
                        return `${labelText}: ${valueText}`;
                    },
                    title: (tooltipItems) => {
                        if (this.chartType === 'open-rate') {
                            if (tooltipItems.length) {
                                return tooltipItems[0].xLabel;
                            } else {
                                return '';
                            }
                        }
                        return moment(tooltipItems[0].xLabel).format(DATE_FORMAT);
                    }
                }
            },
            hover: {
                mode: 'index',
                intersect: false,
                animationDuration: 120
            },
            legend: {
                display: false
            },
            scales: {
                xAxes: [{
                    labelString: 'Date',
                    gridLines: {
                        drawTicks: false,
                        color: (this.nightShift ? '#333F44' : '#DDE1E5'),
                        zeroLineColor: (this.nightShift ? '#333F44' : '#DDE1E5')
                    },
                    ticks: {
                        display: false,
                        maxRotation: 0,
                        minRotation: 0,
                        padding: 6,
                        autoSkip: false,
                        fontColor: '#626D79',
                        maxTicksLimit: 10,
                        callback: (value, index, values) => {
                            let step = (values.length - 1) / (maxTicksAllowed);
                            let steps = [];
                            for (let i = 0; i < maxTicksAllowed; i++) {
                                steps.push(Math.ceil(i * step));
                            }

                            if (index === 0) {
                                return value;
                            }
                            if (index === (values.length - 1) && this.chartType !== 'open-rate') {
                                return 'Today';
                            }

                            if (steps.includes(index)) {
                                return '';
                            }
                        }
                    }
                }],
                yAxes: [{
                    gridLines: {
                        drawTicks: false,
                        display: false,
                        drawBorder: false
                    },
                    ticks: {
                        maxTicksLimit: 5,
                        fontColor: '#7C8B9A',
                        padding: 8,
                        precision: 0,
                        callback: (value) => {
                            const currency = this.chartType === 'mrr' ? getSymbol(this.stats.currency) : '';
                            if (parseInt(value) >= 1000) {
                                return currency + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                            } else {
                                return currency + value;
                            }
                        }
                    }
                }]
            }
        };

        if (this.chartType === 'mrr' || this.chartType === 'all-members') {
            const chartData = this.chartData.datasets[0].data;
            let allZeros = true;
            for (let i = 0; i < chartData.length; i++) {
                const element = chartData[i];
                if (element !== 0) {
                    allZeros = false;
                    break;
                }
            }
            if (allZeros) {
                options.scales.yAxes[0].ticks.suggestedMin = 0;
                options.scales.yAxes[0].ticks.suggestedMax = 100;
            }
        }

        if (this.chartType === 'open-rate') {
            options.scales.yAxes[0].ticks.suggestedMin = 0;
        }

        if (this.isSmall) {
            options.scales.yAxes[0].ticks.display = false;
            options.scales.xAxes[0].gridLines.display = true;
        }
        this.set('chartOptions', options);
    },

    getTicksForRange(rangeInDays) {
        if (rangeInDays <= 30) {
            return 5;
        } else if (rangeInDays <= 90) {
            return 10;
        } else {
            return 15;
        }
    },

    setChartJSDefaults() {
        Chart.defaults.LineWithLine = Chart.defaults.line;
        Chart.controllers.LineWithLine = Chart.controllers.line.extend({
            draw: function (ease) {
                Chart.controllers.line.prototype.draw.call(this, ease);

                if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
                    let activePoint = this.chart.tooltip._active[0];
                    let ctx = this.chart.ctx;
                    let x = activePoint.tooltipPosition().x;
                    let topY = this.chart.scales['y-axis-0'].top;
                    let bottomY = this.chart.scales['y-axis-0'].bottom;

                    // draw line
                    ctx.save();
                    ctx.beginPath();
                    ctx.moveTo(x, topY);
                    ctx.lineTo(x, bottomY);
                    ctx.lineWidth = 1;
                    ctx.strokeStyle = (this.nightShift ? 'rgba(62, 176, 239, 0.65)' : 'rgba(62, 176, 239, 0.1)');
                    ctx.stroke();
                    ctx.restore();
                }
            }
        });
    }
});
