/**
 * WordPress dependencies
 */
import { _x, sprintf } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import { numberFormat } from '@nab/i18n';
import { Line } from 'react-chartjs-2';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import 'chartjs-adapter-moment';
import {
	Chart as ChartJS,
	BarElement,
	CategoryScale,
	Legend,
	LineElement,
	LinearScale,
	PointElement,
	TimeScale,
	Title,
	Tooltip,
} from 'chart.js';
import { COLORS, getLetter, isNumber } from '@nab/utils';

ChartJS.register(
	BarElement,
	CategoryScale,
	ChartDataLabels,
	Legend,
	LineElement,
	LinearScale,
	PointElement,
	TimeScale,
	Title,
	Tooltip
);

import type { ChartDataset, ChartOptions, ScatterDataPoint } from 'chart.js';
import type { AlternativeTrackingData, GoalId, Maybe } from '@nab/types';

/**
 * Internal dependencies
 */
import { isTooltipContext } from './helpers';

export type ConversionRatesTimelineProps = {
	readonly alternatives?: ReadonlyArray< AlternativeTrackingData >;
	readonly goal: GoalId;
	readonly unique: boolean;
};

export const ConversionRatesTimelineChart = (
	props: ConversionRatesTimelineProps
): JSX.Element => {
	const { alternatives = [], goal, unique } = props;

	const datasets: ChartDataset[] = [];
	const colors = [
		COLORS.nabBackgroundAlternativeA,
		COLORS.nabBackgroundAlternativeB,
		COLORS.nabBackgroundAlternativeC,
		COLORS.nabBackgroundAlternativeD,
		COLORS.nabBackgroundAlternativeE,
		COLORS.nabBackgroundAlternativeF,
	];

	datasets.push( {
		label: _x( 'Variant A (Control)', 'text', 'nelio-ab-testing' ),
		backgroundColor: colors[ 0 ],
		borderColor: colors[ 0 ],
		fill: false,
		tension: 0.4,
		data: getData( alternatives[ 0 ], goal, unique ),
	} );

	const numberOfAlternatives = alternatives.length;
	for ( let i = 1; i < numberOfAlternatives; ++i ) {
		datasets.push( {
			label: sprintf(
				/* translators: %s: Letter, such as A, B, or C. */
				_x( 'Variant %s', 'text', 'nelio-ab-testing' ),
				getLetter( i )
			),
			backgroundColor: colors[ i % colors.length ],
			borderColor: colors[ i % colors.length ],
			fill: false,
			tension: 0.4,
			data: getData( alternatives[ i ], goal, unique ),
		} );
	}

	const chartData = { datasets };
	const options = getOptions();

	// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
	return <Line data={ chartData as any } options={ options as any } />;
};

// =======
// HELPERS
// =======

const getOptions = (): ChartOptions => {
	return {
		layout: {
			padding: {
				left: 0,
				right: 10,
				top: 0,
				bottom: 0,
			},
		},
		responsive: true,
		maintainAspectRatio: false,
		scales: {
			x: {
				type: 'time',
				ticks: {
					autoSkip: true,
					autoSkipPadding: 10,
					maxRotation: 0,
				},
				time: {
					unit: 'day',
					displayFormats: {
						day: 'D. MMM',
					},
				},
			},
			y: {
				min: 0,
				ticks: {
					callback: ( value: unknown ) =>
						isNumber( value ) ? `${ value }%` : '',
				},
				title: {
					display: true,
					text: _x( 'Conversion Rate', 'text', 'nelio-ab-testing' ),
				},
			},
		},
		plugins: {
			tooltip: {
				callbacks: {
					title: ( [ context ] ) =>
						isTooltipContext< { x: string } >( context )
							? context.raw.x
							: '',
					label: ( context ) => {
						if ( ! isTooltipContext< { y: number } >( context ) ) {
							return '';
						}
						const value = numberFormat( context.raw.y || 0 );
						return `${ context.dataset.label }: ${ value }%`;
					},
				},
			},
			legend: {
				labels: {
					usePointStyle: true,
					font: {
						family: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif',
						size: 12,
						style: 'normal',
					},
				},
				position: 'bottom',
			},
			datalabels: { display: false },
		},
	};
};

const getData = (
	alternative: Maybe< AlternativeTrackingData >,
	goal: GoalId,
	unique: boolean
): ScatterDataPoint[] => {
	if ( ! alternative ) {
		return [];
	}

	const timeline = alternative.timeline;

	return timeline.map( ( day ) => {
		const visits = unique ? day.uniqueVisits : day.visits;
		const conversions = unique
			? day.uniqueConversions[ goal ] || 0
			: day.conversions[ goal ] || 0;

		let conversionRate = 0;
		if ( visits ) {
			conversionRate =
				Math.round( ( 10000 * conversions ) / visits ) / 100;
		}

		return {
			x: day.date,
			y: conversionRate,
			// eslint-disable-next-line @typescript-eslint/no-explicit-any
		} as any as ScatterDataPoint;
	} );
};
