/* global Color */
/* eslint no-unused-vars: off */
/**
 * Color Calculations.
 *
 * @since Twenty Twenty 1.0
 *
 * @param {string} backgroundColor - The background color.
 * @param {number} accentHue - The hue for our accent color.
 *
 * @return {Object} - this
 */
function _twentyTwentyColor( backgroundColor, accentHue ) {
	// Set the object properties.
	this.backgroundColor = backgroundColor;
	this.accentHue = accentHue;
	this.bgColorObj = new Color( backgroundColor );
	this.textColorObj = this.bgColorObj.getMaxContrastColor();
	this.textColor = this.textColorObj.toCSS();
	this.isDark = 0.5 > this.bgColorObj.toLuminosity();
	this.isLight = ! this.isDark;

	// Return the object.
	return this;
}

/**
 * Builds an array of Color objects based on the accent hue.
 * For improved performance we only build half the array
 * depending on dark/light background-color.
 *
 * @since Twenty Twenty 1.0
 *
 * @return {Object} - this
 */
_twentyTwentyColor.prototype.setAccentColorsArray = function() {
	var self = this,
		minSaturation = 65,
		maxSaturation = 100,
		minLightness = 30,
		maxLightness = 80,
		stepSaturation = 2,
		stepLightness = 2,
		pushColor = function() {
			var colorObj = new Color( {
					h: self.accentHue,
					s: s,
					l: l
				} ),
				item,
				/**
				 * Get a score for this color in contrast to its background color and surrounding text.
				 *
				 * @since Twenty Twenty 1.0
				 *
				 * @param {number} contrastBackground - WCAG contrast with the background color.
				 * @param {number} contrastSurroundingText - WCAG contrast with surrounding text.
				 * @return {number} - 0 is best, higher numbers have bigger difference with the desired scores.
				 */
				getScore = function( contrastBackground, contrastSurroundingText ) {
					var diffBackground = ( 7 >= contrastBackground ) ? 0 : 7 - contrastBackground,
						diffSurroundingText = ( 3 >= contrastSurroundingText ) ? 0 : 3 - contrastSurroundingText;

					return diffBackground + diffSurroundingText;
				};

			item = {
				color: colorObj,
				contrastBackground: colorObj.getDistanceLuminosityFrom( self.bgColorObj ),
				contrastText: colorObj.getDistanceLuminosityFrom( self.textColorObj )
			};

			// Check a minimum of 4.5:1 contrast with the background and 3:1 with surrounding text.
			if ( 4.5 > item.contrastBackground || 3 > item.contrastText ) {
				return;
			}

			// Get a score for this color by multiplying the 2 contrasts.
			// We'll use that to sort the array.
			item.score = getScore( item.contrastBackground, item.contrastText );

			self.accentColorsArray.push( item );
		},
		s, l, aaa;

	this.accentColorsArray = [];

	// We're using `for` loops here because they perform marginally better than other loops.
	for ( s = minSaturation; s <= maxSaturation; s += stepSaturation ) {
		for ( l = minLightness; l <= maxLightness; l += stepLightness ) {
			pushColor( s, l );
		}
	}

	// Check if we have colors that are AAA compliant.
	aaa = this.accentColorsArray.filter( function( color ) {
		return 7 <= color.contrastBackground;
	} );

	// If we have AAA-compliant colors, always prefer them.
	if ( aaa.length ) {
		this.accentColorsArray = aaa;
	}

	// Sort colors by contrast.
	this.accentColorsArray.sort( function( a, b ) {
		return a.score - b.score;
	} );
	return this;
};

/**
 * Get accessible text-color.
 *
 * @since Twenty Twenty 1.0
 *
 * @return {Color} - Returns a Color object.
 */
_twentyTwentyColor.prototype.getTextColor = function() {
	return this.textColor;
};

/**
 * Get accessible color for the defined accent-hue and background-color.
 *
 * @since Twenty Twenty 1.0
 *
 * @return {Color} - Returns a Color object.
 */
_twentyTwentyColor.prototype.getAccentColor = function() {
	var fallback;

	// If we have colors returns the 1st one - it has the highest score.
	if ( this.accentColorsArray[0] ) {
		return this.accentColorsArray[0].color;
	}

	// Fallback.
	fallback = new Color( 'hsl(' + this.accentHue + ',75%,50%)' );
	return fallback.getReadableContrastingColor( this.bgColorObj, 4.5 );
};

/**
 * Return a new instance of the _twentyTwentyColor object.
 *
 * @since Twenty Twenty 1.0
 *
 * @param {string} backgroundColor - The background color.
 * @param {number} accentHue - The hue for our accent color.
 * @return {Object} - this
 */
function twentyTwentyColor( backgroundColor, accentHue ) {// jshint ignore:line
	var color = new _twentyTwentyColor( backgroundColor, accentHue );
	color.setAccentColorsArray();
	return color;
}
