'use strict';

const findAtRuleContext = require('../../utils/findAtRuleContext');
const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
const isStandardSyntaxSelector = require('../../utils/isStandardSyntaxSelector');
const keywordSets = require('../../reference/keywordSets');
const nodeContextLookup = require('../../utils/nodeContextLookup');
const optionsMatches = require('../../utils/optionsMatches');
const parseSelector = require('../../utils/parseSelector');
const report = require('../../utils/report');
const resolvedNestedSelector = require('postcss-resolve-nested-selector');
const ruleMessages = require('../../utils/ruleMessages');
const specificity = require('specificity');
const validateOptions = require('../../utils/validateOptions');

const ruleName = 'no-descending-specificity';

const messages = ruleMessages(ruleName, {
	rejected: (b, a) => `Expected selector "${b}" to come before selector "${a}"`,
});

/** @type {import('stylelint').Rule} */
const rule = (primary, secondaryOptions) => {
	return (root, result) => {
		const validOptions = validateOptions(
			result,
			ruleName,
			{
				actual: primary,
			},
			{
				optional: true,
				actual: secondaryOptions,
				possible: {
					ignore: ['selectors-within-list'],
				},
			},
		);

		if (!validOptions) {
			return;
		}

		const selectorContextLookup = nodeContextLookup();

		root.walkRules((ruleNode) => {
			// Ignore nested property `foo: {};`
			if (!isStandardSyntaxRule(ruleNode)) {
				return;
			}

			// Ignores selectors within list of selectors
			if (
				optionsMatches(secondaryOptions, 'ignore', 'selectors-within-list') &&
				ruleNode.selectors.length > 1
			) {
				return;
			}

			const comparisonContext = selectorContextLookup.getContext(
				ruleNode,
				findAtRuleContext(ruleNode),
			);

			for (const selector of ruleNode.selectors) {
				const trimSelector = selector.trim();

				// Ignore `.selector, { }`
				if (trimSelector === '') {
					continue;
				}

				// The edge-case of duplicate selectors will act acceptably
				const index = ruleNode.selector.indexOf(trimSelector);

				// Resolve any nested selectors before checking
				for (const resolvedSelector of resolvedNestedSelector(selector, ruleNode)) {
					parseSelector(resolvedSelector, result, ruleNode, (s) => {
						if (!isStandardSyntaxSelector(resolvedSelector)) {
							return;
						}

						checkSelector(s, ruleNode, index, comparisonContext);
					});
				}
			}
		});

		/**
		 * @param {import('postcss-selector-parser').Root} selectorNode
		 * @param {import('postcss').Rule} ruleNode
		 * @param {number} sourceIndex
		 * @param {Map<any, any>} comparisonContext
		 */
		function checkSelector(selectorNode, ruleNode, sourceIndex, comparisonContext) {
			const selector = selectorNode.toString();
			const referenceSelectorNode = lastCompoundSelectorWithoutPseudoClasses(selectorNode);
			const selectorSpecificity = specificity.calculate(selector)[0].specificityArray;
			const entry = { selector, specificity: selectorSpecificity };

			if (!comparisonContext.has(referenceSelectorNode)) {
				comparisonContext.set(referenceSelectorNode, [entry]);

				return;
			}

			/** @type {Array<{ selector: string, specificity: import('specificity').SpecificityArray }>} */
			const priorComparableSelectors = comparisonContext.get(referenceSelectorNode);

			for (const priorEntry of priorComparableSelectors) {
				if (specificity.compare(selectorSpecificity, priorEntry.specificity) === -1) {
					report({
						ruleName,
						result,
						node: ruleNode,
						message: messages.rejected(selector, priorEntry.selector),
						index: sourceIndex,
					});
				}
			}

			priorComparableSelectors.push(entry);
		}
	};
};

/**
 * @param {import('postcss-selector-parser').Root} selectorNode
 */
function lastCompoundSelectorWithoutPseudoClasses(selectorNode) {
	const nodesByCombinator = selectorNode.nodes[0].split((node) => node.type === 'combinator');
	const nodesAfterLastCombinator = nodesByCombinator[nodesByCombinator.length - 1];

	const nodesWithoutPseudoClasses = nodesAfterLastCombinator
		.filter((node) => {
			return node.type !== 'pseudo' || keywordSets.pseudoElements.has(node.value.replace(/:/g, ''));
		})
		.join('');

	return nodesWithoutPseudoClasses.toString();
}

rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;
