/// Output custom Font-face declarations and register the family and variants with o-fonts.
///
/// @example This example shows registering a custom font "MyFont" with "sans" fallback. The font allows regular or bold variants.
/// 	@include oFontsDefineCustomFont('MyFont, sans', (
/// 		(weight: regular, style: normal),
/// 		(weight: bold, style: normal)
/// 	)) {
/// 		@font-face {
/// 			src: url('MyFont-Thin.woff2') format('woff2'), url('MyFont-Thin.woff') format('woff');
/// 			font-family: MyFont;
/// 			font-weight: 100;
/// 			font-style: normal;
/// 		}
///
/// 		@font-face{
/// 			src: url('MyFont-Bold.woff2') format('woff2'), url('MyFont-Bold.woff') format('woff');
/// 			font-family: MyFont;
/// 			font-weight: 700;
/// 			font-style: normal;
/// 		}
/// 	};
///
/// @param {String} $font-family The custom font family with fallback e.g. 'ComicSans, sans'
/// @param {Map} $variants The variants (weight and style combinations) which are allowed in a nested map e.g. ((weight: bold, style: normal), (weight: regular, style: normal))
/// @content If the font family is not a system font, output the font-face for the custom font in the mixin content.
@mixin oFontsDefineCustomFont($font-family, $variants) {
	// Validate variants.
	@each $variant in $variants {
		$weight: map-get($variant, 'weight');
		$style: map-get($variant, 'style');
		@if type-of($weight) != 'string' and map-has-key($_o-fonts-weights, $weight) {
			@error 'Could not include custom font "#{$font-family}". All variants must specify a weight, one of "#{$_o-fonts-weights}".';
		}
		@if type-of($style) != 'string' {
			@error 'Could not include custom font "#{$font-family}". All variants must specify a style, e.g. "normal", "italic".';
		}
	}
	$font-key: oFontsGetFontFamilyWithoutFallbacks($font-family);
	$_o-fonts-families: map-merge(($font-key: (
		'font-family': $font-family,
		'variants': $variants,
		'custom': true
	)), $_o-fonts-families) !global;
	@content; // Output a custom Font-face declaration.
}

/// Register which fonts have been output by already for your project.
/// This mixin is useful if a project calls the `oFonts` mixin is in a different
/// entry point.
///
/// @example Include all fonts for the current brand (core, internal, whitelabel).
///     @include oFontsVariantsIncluded();
///
/// @example Include a limited set of recommended fonts for the current brand (core, internal, whitelabel).
///     @include oFontsVariantsIncluded($opts: ('recommended': true));
///
/// @example Include a limited set of recommended fonts for the current brand, plus an extra FinancierDisplayWeb font.
/// 	@include oFontsVariantsIncluded($opts: (
/// 		'recommended': true,
/// 		'financier-display': (
/// 			(weight: regular, style: normal)
/// 		)
/// 	));
///
/// @example Include only regular and semibold MetricWeb font faces.
///     @include oFontsVariantsIncluded($opts: ('metric': (
///     	(weight: regular, style: normal),
///     	(weight: semibold, style: normal),
///     )));
///
/// @example Include only regular and bold FinancierDisplayWeb font faces.
///     @include oFontsVariantsIncluded($opts: ('financier-display': (
///     	(weight: regular, style: normal),
///     	(weight: semibold, style: normal),
///     )));
///
/// @example Include only regular font faces for MetricWeb and FinancierDisplayWeb.
///     @include oFontsVariantsIncluded($opts: (
///     	'metric': ((weight: regular, style: normal)),
///     	'financier-display': ((weight: regular, style: normal))
///     ));
/// @param {Map} $opts - the font faces to included, see the README or examples for more details.
/// @see oFonts - Use `oFonts` to include font faces.
@mixin oFontsVariantsIncluded($opts: $_o-fonts-default) {
	$variants: _oFontsOptionsToVariants($opts);

	@each $variant in $variants {
		$family: map-get($variant, 'family');
		$weight: map-get($variant, 'weight');
		$style: map-get($variant, 'style');
		@include _oFontsVariantIncluded($family, $weight, $style);
	}
}

/// Output a Font-face declaration for a given font family which is provided by Origami.
///
/// @param {String} $family - one of $_o-fonts-families
/// @param {String} $weight [regular] - e.g. 'regular', 'semibold', 'bold'
/// @param {String} $style [normal] - e.g. 'italic'
/// @param {String|Null} $display - the font-display property for this font face, defaults to $o-fonts-display
/// @access private
@mixin _oFontsInclude($family, $weight: regular, $style: normal, $display: $o-fonts-display) {
	// Help user if they requested a normal rather than regular weight.
	@if $weight == normal {
		@warn '"normal" is not a font weight for "#{$family}". Request a "regular" weight instead.';
		$weight: regular;
	}

	// Check the font is an Origami font, not a custom font.
	@if map-has-key($_o-fonts-families, $family) {
		$font-family-config: map-get($_o-fonts-families, $family);
		@if map-get($font-family-config, 'custom') {
			@error 'Can not include a custom font "#{$family}". Include your custom font manually.';
		}
	}

	// Check if the font has already been included
	// If so, no need to output another @font-face declaration
	$font-is-already-included: oFontsVariantIncluded($family, $weight, $style);

	@if $font-is-already-included == false {
		// Error if a font does not exist for the given variant.
		@if not map-has-key($_o-fonts-families, $family) {
			@error 'Font "#{inspect($family)}" not found. Must be one of #{map-keys($_o-fonts-families)}.';
		}

		@if not oFontsVariantExists($family, $weight, $style) {
			@error 'Font for "#{$family}" at weight: "#{$weight}" and style "#{$style}" does not exist.';
		}

		// Files are named as follows
		// Name-WeightType
		// MetricWeb-Regular              (regular normal)
		// MetricWeb-RegularItalic        (regular italic)
		// MetricWeb-Bold                 (bold normal)
		// MetricWeb-BoldItalic           (bold italic)

		// By default, suffix is the weight
		$font-suffix: _oFontsStringCapitalise($weight);
		@if ($style != 'normal') {
			$capitalised-weight: _oFontsStringCapitalise($weight);
			$capitalised-style: _oFontsStringCapitalise($style);
			$font-suffix: #{$capitalised-weight}#{$capitalised-style};
		}

		$font-file: '#{$family}-#{$font-suffix}';
		// set path for self hosted font
		$self-host-path: $o-fonts-self-host-path + $font-file;
		// set path using existing o-fonts-path variable, for font hosted on Build Service api implementation
		$build-service-path: $o-fonts-build-service-path + '&font_name=#{$font-file}&system_code=origami';

		// use $o-fonts-self-host-path if set, $o-fonts-build-service-path otherwise
		$font-url-woff: if($o-fonts-self-host-path == '', '#{$build-service-path}&font_format=woff', '#{$self-host-path}.woff');
		$font-url-woff2: if($o-fonts-self-host-path == '', '#{$build-service-path}&font_format=woff2', '#{$self-host-path}.woff2');

		@font-face {
			src: url($font-url-woff2) format('woff2'), url($font-url-woff) format('woff');
			font-family: $family;
			font-weight: oFontsWeight($weight);
			font-style: unquote($style);
			font-display: unquote($display);
		}

		// Add to the list of already included families / variants
		@include _oFontsVariantIncluded($family, $weight, $style);
	}
}

/// Log a given font variant as having been output.
///
/// @param {String} $family - one of $_o-fonts-families
/// @param {String} $weight [regular] - The font weight.
/// @param {String} $style [normal] - The font style.
@mixin _oFontsVariantIncluded($family, $weight, $style) {
	// Add to the list of already included families / variants
	$variant-key: _oFontsVariantKey($family, $weight, $style);
	$_o-fonts-families-included: map-merge($_o-fonts-families-included, ($variant-key: true)) !global;
}
