'use strict';

const { isRoot, isAtRule, isRule } = require('./typeGuards');

/** @typedef {import('postcss').Root} Root */
/** @typedef {import('postcss').Root} Document */
/** @typedef {import('postcss').Node} PostcssNode */
/** @typedef {import('postcss').Container} PostcssContainerNode */
/** @typedef {import('postcss').Declaration} Declaration */
/** @typedef {(callbackFn: (decl: Declaration, index: number, decls: Declaration[]) => void) => void} EachDeclaration */

/**
 * @param {PostcssNode} node
 * @returns {node is PostcssContainerNode}
 */
function isContainerNode(node) {
	return isRule(node) || isAtRule(node) || isRoot(node);
}

/**
 * In order to accommodate nested blocks (postcss-nested),
 * we need to run a shallow loop (instead of eachDecl() or eachRule(),
 * which loop recursively) and allow each nested block to accumulate
 * its own list of properties -- so that a property in a nested rule
 * does not conflict with the same property in the parent rule
 * executes a provided function once for each declaration block.
 *
 * @param {Root | Document} root - root element of file.
 * @param {(eachDecl: EachDeclaration) => void} callback - Function to execute for each declaration block
 *
 * @returns {void}
 */
module.exports = function eachDeclarationBlock(root, callback) {
	/**
	 * @param {PostcssNode} statement
	 *
	 * @returns {void}
	 */
	function each(statement) {
		if (!isContainerNode(statement)) return;

		if (statement.nodes && statement.nodes.length) {
			/** @type {Declaration[]} */
			const decls = [];

			for (const node of statement.nodes) {
				if (node.type === 'decl') {
					decls.push(node);
				}

				each(node);
			}

			if (decls.length) {
				callback(decls.forEach.bind(decls));
			}
		}
	}

	each(root);
};
