import {
	aNPlusBNotationPseudoClasses,
	aNPlusBOfSNotationPseudoClasses,
	deprecatedHtmlTypeSelectors,
	deprecatedPseudoClasses,
	deprecatedPseudoElements,
	deprecatedSvgTypeSelectors,
	percentageKeyframeWithNamedEquivalent,
} from '../reference/selectors.mjs';
import {
	colorFunctions,
	hueColorFunctions,
	legacyNotationColorFunctions,
	lightnessColorFunctions,
	mathFunctions,
	withAlphaAliasColorFunctions,
	withoutAlphaAliasColorFunctions,
} from '../reference/functions.mjs';
import {
	displayInsideKeywords,
	displayLegacyKeywords,
	displayListItemKeyword,
	displayOutsideKeywords,
	fontWeightNonNumericKeywords,
	fontWeightNumericKeywordsWithNamedEquivalent,
	fontWeightRelativeKeywords,
	keyframeSelectorKeywords,
	namedColorsKeywords,
	physicalToFlowRelativeValueKeywordsByProperty,
} from '../reference/keywords.mjs';
import {
	flowRelativeUnits,
	lengthUnits,
	physicalToFlowRelativeUnits,
} from '../reference/units.mjs';
import { acceptPropertyNamesProperties } from '../reference/properties.mjs';
import { deprecatedMediaTypesNames } from '../reference/mediaTypes.mjs';
import { nestingSupportedAtKeywords } from '../reference/atKeywords.mjs';
import { prefixes } from '../reference/prefixes.mjs';

const aNPlusBClasses = [
	...aNPlusBNotationPseudoClasses.values(),
	...aNPlusBOfSNotationPseudoClasses.values(),
].join('|');

export const atRuleRegexes = {
	containerName: /^container$/i,
	customMediaName: /^custom-media$/i,
	importName: /^import$/i,
	keyframesName: /^(-(o|moz|ms|webkit)-)?keyframes$/i,
	layerName: /^layer$/i,
	mediaName: /^media$/i,
	pageName: /^page$/i,
	propertyName: /^property$/i,
	scopeName: /^scope$/i,
	unsupportedNestingNames: new RegExp(
		`^((?!${[...nestingSupportedAtKeywords.values()].join('|')}).)*$`,
		'i',
	),
};

export const descriptorRegexes = {
	syntaxName: /^syntax$/i,
};

export const propertyRegexes = {
	propertyAcceptingNames: new RegExp(`^(?:${[...acceptPropertyNamesProperties].join('|')})$`, 'i'),
	containerNameAndShorthandName: /^container(-name)?$/i,
	custom: /^--/,
	fontFamilyAndShorthandName: /^font(-family)?$/i,
	fontWeightAndShorthandName: /^font(-weight)?$/i,
	gridAreaNames: /^(?:grid|grid-template|grid-template-areas)$/i,
	layoutMappings: new RegExp(
		`^(?:${[...physicalToFlowRelativeValueKeywordsByProperty.keys()].join('|')})$`,
		'i',
	),
};

export const mayIncludeRegexes = {
	aNPlusBNotationPseudoClass: new RegExp(`\\b:(?:${aNPlusBClasses})\\(`, 'i'),
	annotation: /!/,
	attributeSelector: /\[/,
	attributeSelectorWithOperator: /\[.*=/,
	axisUnit: new RegExp(
		`\\d(?:${[...physicalToFlowRelativeUnits.keys(), ...flowRelativeUnits].join('|')})\\b`,
		'i',
	),
	classSelector: /\./,
	colorFunction: new RegExp(`\\b(?:${[...colorFunctions.values()].join('|')})\\(`, 'i'),
	legacyNotationColorFunction: new RegExp(
		`\\b(?:${[...legacyNotationColorFunctions.values()].join('|')})\\(`,
		'i',
	),
	combinator: /[>+~\s]/,
	customProperty: /--/,
	deprecatedMediaType: new RegExp(`\\b(?:${[...deprecatedMediaTypesNames].join('|')})\\b`, 'i'),
	deprecatedPseudo: new RegExp(
		`\\:(?:${[...deprecatedPseudoClasses, ...deprecatedPseudoElements].join('|')})\\b`,
		'i',
	),
	deprecatedTypeSelector: new RegExp(
		`\\b(?:${[...deprecatedHtmlTypeSelectors, ...deprecatedSvgTypeSelectors].join('|')})\\b`,
		'i',
	),
	displayKeyword: new RegExp(
		`\\b(?:${[...displayListItemKeyword, ...displayOutsideKeywords, ...displayInsideKeywords, ...displayLegacyKeywords].join('|')})\\b`,
		'i',
	),
	dimension: /\d[%\w-]/,
	dirPseudoClass: /:dir\(/i,
	grayFunction: /\bgray\(/i,
	hexColor: /#[\da-z]+/i,
	hueColorFunction: new RegExp(`\\b(?:${[...hueColorFunctions.values()].join('|')})\\(`, 'i'),
	lightnessColorFunction: new RegExp(
		`\\b(?:${[...lightnessColorFunctions.values()].join('|')})\\(`,
		'i',
	),
	idClassAttributeSelector: /[#.[]/,
	idSelector: /#/,
	keyword: /(?<![0-9])[a-z]+(?!\()/i,
	layerFunction: /\blayer\(/i,
	layoutFlowRelativeKeyword: new RegExp(
		`\\b(?:${[
			...new Set(
				[...physicalToFlowRelativeValueKeywordsByProperty.values()].flatMap((mapping) => [
					...mapping.values(),
				]),
			),
		].join('|')})\\b`,
		'i',
	),
	layoutPhysicalKeyword: new RegExp(
		`\\b(?:${[
			...new Set(
				[...physicalToFlowRelativeValueKeywordsByProperty.values()].flatMap((mapping) => [
					...mapping.keys(),
				]),
			),
		].join('|')})\\b`,
		'i',
	),
	mathFunction: new RegExp(`\\b(?:${[...mathFunctions.values()].join('|')})\\(`, 'i'),
	namedFontWeight: new RegExp(
		`\\b(?:${[...new Set([...fontWeightNonNumericKeywords, ...fontWeightRelativeKeywords])].join('|')})\\b`,
		'i',
	),
	numericFontWeight: new RegExp(
		`\\b(?:${[...fontWeightNumericKeywordsWithNamedEquivalent.values()].join('|')})\\b`,
	),
	namedKeyframeSelectorWithPercentageEquivalent: new RegExp(
		`\\b(?:${[...keyframeSelectorKeywords.values()].join('|')})\\b`,
		'i',
	),
	percentageKeyframeSelectorWithNamedEquivalent: new RegExp(
		`(?:^|[,\\s])(?:${[...percentageKeyframeWithNamedEquivalent.values()].join('|')})`,
	),
	multipleValues: /\s|,/,
	namedColor: new RegExp(`\\b(?:${[...namedColorsKeywords.values()].join('|')})\\b`, 'i'),
	nestingSelector: /&/,
	notPseudoClass: /:not\(/i,
	operator: /[+-]/,
	prefix: new RegExp(`(?:${[...prefixes].join('|')})`, 'i'),
	pseudo: /:/,
	pseudoElement: /::/,
	time: /\dm?s/i,
	typeSelector: /(?:[^.#[:a-z-]|^)[a-z]/i,
	universalSelector: /\*/,
	urlFunction: /\burl\(/i,
	validHex: /#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})(?:$|[^\da-f])/i,
	varFunction: /\bvar\(/i,
	withAlphaAliasColorFunction: new RegExp(
		`\\b(?:${[...withAlphaAliasColorFunctions.values()].join('|')})\\(`,
		'i',
	),
	withoutAlphaAliasColorFunction: new RegExp(
		`\\b(?:${[...withoutAlphaAliasColorFunctions.values()].join('|')})\\(`,
		'i',
	),
	zeroLength: new RegExp(
		`\\b[+-]?(?:0+|0*\\.\\d+)(?:${[...lengthUnits.values()].join('|')})\\b`,
		'i',
	),
};
