
import { scaleBand, scaleLog } from '@visx/scale';
import { Bar } from '@visx/shape';
import { max, min } from 'd3-array';
import moment from 'moment';
import React from 'react';

import { __, sprintf, _n } from '@wordpress/i18n';

import { Duration } from '../../utils/admin';

type Datum = {
	index: number,
	count: number,
	zeroData?: boolean,
};

type Props = {
	histogram: Datum[],
	maxViews?: number,
	width?: number,
	height?: number,
	period?: Duration,
};

type Breakpoints = {
	[ k in Duration ]: number;
};

const getX = ( d : Datum ) => d.index;
const getY = ( d : Datum ) => d?.count || 0;

export default function SparkChart( props: Props ) {
	const breakPoints : Breakpoints = {
		'PT30M': 30,
		'P7D': 100,
		'P14D': 110,
		'P30D': 120,
		'P1M': 120,
		'P60D': 135,
		'P90D': 150,
	};

	// Set up default empty histogram to allow for animations.
	const days = Math.floor( moment.duration( props.period || 'P7D' ).asDays() );
	let histogram : Datum[] = Array( days ).fill( {
		index: 0,
		count: 0,
	} );

	histogram.forEach( ( d, i ) => {
		histogram[i] = {
			index: i,
			count: 0,
		};
	} );

	if ( props.histogram && props.histogram.length > 0 ) {
		if ( props.histogram.length < 7 ) {
			histogram.splice( 7 - props.histogram.length, Infinity, ...props.histogram );
		} else {
			histogram = props.histogram;
		}
	}

	const {
		width = 160,
		height = 40,
		maxViews,
		period = 'P7D',
	} = props;

	// Override width depending on number of days shown.
	const trueWidth = breakPoints[ period ] || width;

	const yMax = max( histogram, getY ) as number || 0;

	// Pad numbers until we get data, always ensure they're less than real data values.
	for ( let i = 0; i < histogram.length; i++ ) {
		if ( histogram[i].count === 0 ) {
			histogram[i].zeroData = true;
			histogram[i].count = 0.7;
		} else {
			break;
		}
	}

	const xScale = scaleBand<number>( {
		domain: histogram.map( getX ),
		padding: Math.max( 1.5 / histogram.length, 0.15 ),
		range: [ 0, trueWidth ],
	} );
	const yScale = scaleLog<number>( {
		domain: [ 1, maxViews || yMax as number || 0.7 ],
		range: [ height, 0 ],
	} );

	return (
		<svg height={ height } overflow="hidden" width={ trueWidth }>
			{ histogram.map( ( d, i ) => {
				const barWidth = xScale.bandwidth();
				const barX = xScale( getX( d ) );
				const barY = Math.max( 0, Math.min( yScale( getY( d ) as number + 0.7 ), height - 0.7 ) );
				const barHeight = height - barY;
				return (
					<Bar
						key={ `bar-${ i }` }
						fill={ d.zeroData ? '#ECEEF1' : '#1f2937' }
						fillOpacity={ 0.8 }
						height={ barHeight }
						rx={ 1 }
						width={ barWidth }
						x={ barX }
						y={ barY }
					>
						<title>{
							d.zeroData
								? __( 'No data for this date', 'altis' )
								: sprintf(
									'%d %s on %s',
									d.count,
									_n( 'View', 'Views', d.count, 'altis' ),
									( new Date( d.index ) ).toDateString()
								)
						}</title>
					</Bar>
				);
			} ) }
		</svg>
	);
}
