'use strict';

const beforeBlockString = require('../../utils/beforeBlockString');
const hasBlock = require('../../utils/hasBlock');
const optionsMatches = require('../../utils/optionsMatches');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const styleSearch = require('style-search');
const validateOptions = require('../../utils/validateOptions');
const { isAtRule, isDeclaration, isRoot, isRule } = require('../../utils/typeGuards');
const { isBoolean, isNumber, isString } = require('../../utils/validateTypes');

const ruleName = 'indentation';
const messages = ruleMessages(ruleName, {
	expected: (x) => `Expected indentation of ${x}`,
});

/** @type {import('stylelint').Rule} */
const rule = (primary, secondaryOptions = {}, context) => {
	return (root, result) => {
		const validOptions = validateOptions(
			result,
			ruleName,
			{
				actual: primary,
				possible: [isNumber, 'tab'],
			},
			{
				actual: secondaryOptions,
				possible: {
					baseIndentLevel: [isNumber, 'auto'],
					except: ['block', 'value', 'param'],
					ignore: ['value', 'param', 'inside-parens'],
					indentInsideParens: ['twice', 'once-at-root-twice-in-block'],
					indentClosingBrace: [isBoolean],
				},
				optional: true,
			},
		);

		if (!validOptions) {
			return;
		}

		const spaceCount = isNumber(primary) ? primary : null;
		const indentChar = spaceCount == null ? '\t' : ' '.repeat(spaceCount);
		const warningWord = primary === 'tab' ? 'tab' : 'space';

		/** @type {number | 'auto'} */
		const baseIndentLevel = secondaryOptions.baseIndentLevel;
		/** @type {boolean} */
		const indentClosingBrace = secondaryOptions.indentClosingBrace;

		/**
		 * @param {number} level
		 */
		const legibleExpectation = (level) => {
			const count = spaceCount == null ? level : level * spaceCount;
			const quantifiedWarningWord = count === 1 ? warningWord : `${warningWord}s`;

			return `${count} ${quantifiedWarningWord}`;
		};

		// Cycle through all nodes using walk.
		root.walk((node) => {
			if (isRoot(node)) {
				// Ignore nested template literals root in css-in-js lang
				return;
			}

			const nodeLevel = indentationLevel(node);

			// Cut out any * and _ hacks from `before`
			const before = (node.raws.before || '').replace(/[*_]$/, '');
			const after = ('after' in node.raws && node.raws.after) || '';
			const parent = node.parent;

			if (!parent) throw new Error('A parent node must be present');

			const expectedOpeningBraceIndentation = indentChar.repeat(nodeLevel);

			// Only inspect the spaces before the node
			// if this is the first node in root
			// or there is a newline in the `before` string.
			// (If there is no newline before a node,
			// there is no "indentation" to check.)
			const isFirstChild = parent.type === 'root' && parent.first === node;
			const lastIndexOfNewline = before.lastIndexOf('\n');

			// Inspect whitespace in the `before` string that is
			// *after* the *last* newline character,
			// because anything besides that is not indentation for this node:
			// it is some other kind of separation, checked by some separate rule
			if (
				(lastIndexOfNewline !== -1 ||
					(isFirstChild &&
						(!getDocument(parent) ||
							(parent.raws.codeBefore && parent.raws.codeBefore.endsWith('\n'))))) &&
				before.slice(lastIndexOfNewline + 1) !== expectedOpeningBraceIndentation
			) {
				if (context.fix) {
					if (isFirstChild && isString(node.raws.before)) {
						node.raws.before = node.raws.before.replace(
							/^[ \t]*(?=\S|$)/,
							expectedOpeningBraceIndentation,
						);
					}

					node.raws.before = fixIndentation(node.raws.before, expectedOpeningBraceIndentation);
				} else {
					report({
						message: messages.expected(legibleExpectation(nodeLevel)),
						node,
						result,
						ruleName,
					});
				}
			}

			// Only blocks have the `after` string to check.
			// Only inspect `after` strings that start with a newline;
			// otherwise there's no indentation involved.
			// And check `indentClosingBrace` to see if it should be indented an extra level.
			const closingBraceLevel = indentClosingBrace ? nodeLevel + 1 : nodeLevel;
			const expectedClosingBraceIndentation = indentChar.repeat(closingBraceLevel);

			if (
				(isRule(node) || isAtRule(node)) &&
				hasBlock(node) &&
				after &&
				after.includes('\n') &&
				after.slice(after.lastIndexOf('\n') + 1) !== expectedClosingBraceIndentation
			) {
				if (context.fix) {
					node.raws.after = fixIndentation(node.raws.after, expectedClosingBraceIndentation);
				} else {
					report({
						message: messages.expected(legibleExpectation(closingBraceLevel)),
						node,
						index: node.toString().length - 1,
						result,
						ruleName,
					});
				}
			}

			// If this is a declaration, check the value
			if (isDeclaration(node)) {
				checkValue(node, nodeLevel);
			}

			// If this is a rule, check the selector
			if (isRule(node)) {
				checkSelector(node, nodeLevel);
			}

			// If this is an at rule, check the params
			if (isAtRule(node)) {
				checkAtRuleParams(node, nodeLevel);
			}
		});

		/**
		 * @param {import('postcss').Node} node
		 * @param {number} level
		 * @returns {number}
		 */
		function indentationLevel(node, level = 0) {
			if (!node.parent) throw new Error('A parent node must be present');

			if (isRoot(node.parent)) {
				return level + getRootBaseIndentLevel(node.parent, baseIndentLevel, primary);
			}

			let calculatedLevel;

			// Indentation level equals the ancestor nodes
			// separating this node from root; so recursively
			// run this operation
			calculatedLevel = indentationLevel(node.parent, level + 1);

			// If `secondaryOptions.except` includes "block",
			// blocks are taken down one from their calculated level
			// (all blocks are the same level as their parents)
			if (
				optionsMatches(secondaryOptions, 'except', 'block') &&
				(isRule(node) || isAtRule(node)) &&
				hasBlock(node)
			) {
				calculatedLevel--;
			}

			return calculatedLevel;
		}

		/**
		 * @param {import('postcss').Declaration} decl
		 * @param {number} declLevel
		 */
		function checkValue(decl, declLevel) {
			if (!decl.value.includes('\n')) {
				return;
			}

			if (optionsMatches(secondaryOptions, 'ignore', 'value')) {
				return;
			}

			const declString = decl.toString();
			const valueLevel = optionsMatches(secondaryOptions, 'except', 'value')
				? declLevel
				: declLevel + 1;

			checkMultilineBit(declString, valueLevel, decl);
		}

		/**
		 * @param {import('postcss').Rule} ruleNode
		 * @param {number} ruleLevel
		 */
		function checkSelector(ruleNode, ruleLevel) {
			const selector = ruleNode.selector;

			// Less mixins have params, and they should be indented extra
			// @ts-expect-error -- TS2339: Property 'params' does not exist on type 'Rule'.
			if (ruleNode.params) {
				ruleLevel += 1;
			}

			checkMultilineBit(selector, ruleLevel, ruleNode);
		}

		/**
		 * @param {import('postcss').AtRule} atRule
		 * @param {number} ruleLevel
		 */
		function checkAtRuleParams(atRule, ruleLevel) {
			if (optionsMatches(secondaryOptions, 'ignore', 'param')) {
				return;
			}

			// @nest and SCSS's @at-root rules should be treated like regular rules, not expected
			// to have their params (selectors) indented
			const paramLevel =
				optionsMatches(secondaryOptions, 'except', 'param') ||
				atRule.name === 'nest' ||
				atRule.name === 'at-root'
					? ruleLevel
					: ruleLevel + 1;

			checkMultilineBit(beforeBlockString(atRule).trim(), paramLevel, atRule);
		}

		/**
		 * @param {string} source
		 * @param {number} newlineIndentLevel
		 * @param {import('postcss').Node} node
		 */
		function checkMultilineBit(source, newlineIndentLevel, node) {
			if (!source.includes('\n')) {
				return;
			}

			// Data for current node fixing
			/** @type {Array<{ expectedIndentation: string, currentIndentation: string, startIndex: number }>} */
			const fixPositions = [];

			// `outsideParens` because function arguments and also non-standard parenthesized stuff like
			// Sass maps are ignored to allow for arbitrary indentation
			let parentheticalDepth = 0;

			const ignoreInsideParans = optionsMatches(secondaryOptions, 'ignore', 'inside-parens');

			styleSearch(
				{
					source,
					target: '\n',
					// @ts-expect-error -- The `outsideParens` option is unsupported. Why?
					outsideParens: ignoreInsideParans,
				},
				(match, matchCount) => {
					const precedesClosingParenthesis = /^[ \t]*\)/.test(source.slice(match.startIndex + 1));

					if (ignoreInsideParans && (precedesClosingParenthesis || match.insideParens)) {
						return;
					}

					let expectedIndentLevel = newlineIndentLevel;

					// Modififications for parenthetical content
					if (!ignoreInsideParans && match.insideParens) {
						// If the first match in is within parentheses, reduce the parenthesis penalty
						if (matchCount === 1) parentheticalDepth -= 1;

						// Account for windows line endings
						let newlineIndex = match.startIndex;

						if (source[match.startIndex - 1] === '\r') {
							newlineIndex--;
						}

						const followsOpeningParenthesis = /\([ \t]*$/.test(source.slice(0, newlineIndex));

						if (followsOpeningParenthesis) {
							parentheticalDepth += 1;
						}

						const followsOpeningBrace = /\{[ \t]*$/.test(source.slice(0, newlineIndex));

						if (followsOpeningBrace) {
							parentheticalDepth += 1;
						}

						const startingClosingBrace = /^[ \t]*\}/.test(source.slice(match.startIndex + 1));

						if (startingClosingBrace) {
							parentheticalDepth -= 1;
						}

						expectedIndentLevel += parentheticalDepth;

						// Past this point, adjustments to parentheticalDepth affect next line

						if (precedesClosingParenthesis) {
							parentheticalDepth -= 1;
						}

						switch (secondaryOptions.indentInsideParens) {
							case 'twice':
								if (!precedesClosingParenthesis || indentClosingBrace) {
									expectedIndentLevel += 1;
								}

								break;
							case 'once-at-root-twice-in-block':
								if (node.parent === node.root()) {
									if (precedesClosingParenthesis && !indentClosingBrace) {
										expectedIndentLevel -= 1;
									}

									break;
								}

								if (!precedesClosingParenthesis || indentClosingBrace) {
									expectedIndentLevel += 1;
								}

								break;
							default:
								if (precedesClosingParenthesis && !indentClosingBrace) {
									expectedIndentLevel -= 1;
								}
						}
					}

					// Starting at the index after the newline, we want to
					// check that the whitespace characters (excluding newlines) before the first
					// non-whitespace character equal the expected indentation
					const afterNewlineSpaceMatches = /^([ \t]*)\S/.exec(source.slice(match.startIndex + 1));

					if (!afterNewlineSpaceMatches) {
						return;
					}

					const afterNewlineSpace = afterNewlineSpaceMatches[1];
					const expectedIndentation = indentChar.repeat(
						expectedIndentLevel > 0 ? expectedIndentLevel : 0,
					);

					if (afterNewlineSpace !== expectedIndentation) {
						if (context.fix) {
							// Adding fixes position in reverse order, because if we change indent in the beginning of the string it will break all following fixes for that string
							fixPositions.unshift({
								expectedIndentation,
								currentIndentation: afterNewlineSpace,
								startIndex: match.startIndex,
							});
						} else {
							report({
								message: messages.expected(legibleExpectation(expectedIndentLevel)),
								node,
								index: match.startIndex + afterNewlineSpace.length + 1,
								result,
								ruleName,
							});
						}
					}
				},
			);

			if (fixPositions.length) {
				if (isRule(node)) {
					for (const fixPosition of fixPositions) {
						node.selector = replaceIndentation(
							node.selector,
							fixPosition.currentIndentation,
							fixPosition.expectedIndentation,
							fixPosition.startIndex,
						);
					}
				}

				if (isDeclaration(node)) {
					const declProp = node.prop;
					const declBetween = node.raws.between;

					if (!isString(declBetween)) {
						throw new TypeError('The `between` property must be a string');
					}

					for (const fixPosition of fixPositions) {
						if (fixPosition.startIndex < declProp.length + declBetween.length) {
							node.raws.between = replaceIndentation(
								declBetween,
								fixPosition.currentIndentation,
								fixPosition.expectedIndentation,
								fixPosition.startIndex - declProp.length,
							);
						} else {
							node.value = replaceIndentation(
								node.value,
								fixPosition.currentIndentation,
								fixPosition.expectedIndentation,
								fixPosition.startIndex - declProp.length - declBetween.length,
							);
						}
					}
				}

				if (isAtRule(node)) {
					const atRuleName = node.name;
					const atRuleAfterName = node.raws.afterName;
					const atRuleParams = node.params;

					if (!isString(atRuleAfterName)) {
						throw new TypeError('The `afterName` property must be a string');
					}

					for (const fixPosition of fixPositions) {
						// 1 — it's a @ length
						if (fixPosition.startIndex < 1 + atRuleName.length + atRuleAfterName.length) {
							node.raws.afterName = replaceIndentation(
								atRuleAfterName,
								fixPosition.currentIndentation,
								fixPosition.expectedIndentation,
								fixPosition.startIndex - atRuleName.length - 1,
							);
						} else {
							node.params = replaceIndentation(
								atRuleParams,
								fixPosition.currentIndentation,
								fixPosition.expectedIndentation,
								fixPosition.startIndex - atRuleName.length - atRuleAfterName.length - 1,
							);
						}
					}
				}
			}
		}
	};
};

/**
 * @param {import('postcss').Root} root
 * @param {number | 'auto'} baseIndentLevel
 * @param {string} space
 * @returns {number}
 */
function getRootBaseIndentLevel(root, baseIndentLevel, space) {
	const document = getDocument(root);

	if (!document) {
		return 0;
	}

	if (!root.source) {
		throw new Error('The root node must have a source');
	}

	/** @type {import('postcss').Source & { baseIndentLevel?: number }} */
	const source = root.source;

	const indentLevel = source.baseIndentLevel;

	if (isNumber(indentLevel) && Number.isSafeInteger(indentLevel)) {
		return indentLevel;
	}

	const newIndentLevel = inferRootIndentLevel(root, baseIndentLevel, () =>
		inferDocIndentSize(document, space),
	);

	source.baseIndentLevel = newIndentLevel;

	return newIndentLevel;
}

/**
 * @param {import('postcss').Node} node
 */
function getDocument(node) {
	// @ts-expect-error -- TS2339: Property 'document' does not exist on type 'Node'.
	const document = node.document;

	if (document) {
		return document;
	}

	const root = node.root();

	// @ts-expect-error -- TS2339: Property 'document' does not exist on type 'Node'.
	return root && root.document;
}

/**
 * @param {import('postcss').Document} document
 * @param {string} space
 * returns {number}
 */
function inferDocIndentSize(document, space) {
	if (!document.source) throw new Error('The document node must have a source');

	/** @type {import('postcss').Source & { indentSize?: number }} */
	const docSource = document.source;

	let indentSize = docSource.indentSize;

	if (isNumber(indentSize) && Number.isSafeInteger(indentSize)) {
		return indentSize;
	}

	const source = document.source.input.css;
	const indents = source.match(/^ *(?=\S)/gm);

	if (indents) {
		/** @type {Map<number, number>} */
		const scores = new Map();
		let lastIndentSize = 0;
		let lastLeadingSpacesLength = 0;

		/**
		 * @param {number} leadingSpacesLength
		 */
		const vote = (leadingSpacesLength) => {
			if (leadingSpacesLength) {
				lastIndentSize = Math.abs(leadingSpacesLength - lastLeadingSpacesLength) || lastIndentSize;

				if (lastIndentSize > 1) {
					const score = scores.get(lastIndentSize);

					if (score) {
						scores.set(lastIndentSize, score + 1);
					} else {
						scores.set(lastIndentSize, 1);
					}
				}
			} else {
				lastIndentSize = 0;
			}

			lastLeadingSpacesLength = leadingSpacesLength;
		};

		for (const leadingSpaces of indents) {
			vote(leadingSpaces.length);
		}

		let bestScore = 0;

		for (const [indentSizeDate, score] of scores.entries()) {
			if (score > bestScore) {
				bestScore = score;
				indentSize = indentSizeDate;
			}
		}
	}

	indentSize = Number(indentSize) || (indents && indents[0].length) || Number(space) || 2;
	docSource.indentSize = indentSize;

	return indentSize;
}

/**
 * @param {import('postcss').Root} root
 * @param {number | 'auto'} baseIndentLevel
 * @param {() => number} indentSize
 * @returns {number}
 */
function inferRootIndentLevel(root, baseIndentLevel, indentSize) {
	/**
	 * @param {string} indent
	 */
	function getIndentLevel(indent) {
		const tabMatch = indent.match(/\t/g);
		const tabCount = tabMatch ? tabMatch.length : 0;

		const spaceMatch = indent.match(/ /g);
		const spaceCount = spaceMatch ? Math.round(spaceMatch.length / indentSize()) : 0;

		return tabCount + spaceCount;
	}

	let newBaseIndentLevel = 0;

	if (!isNumber(baseIndentLevel) || !Number.isSafeInteger(baseIndentLevel)) {
		if (!root.source) throw new Error('The root node must have a source');

		let source = root.source.input.css;

		source = source.replace(/^[^\r\n]+/, (firstLine) => {
			const match = root.raws.codeBefore && /(?:^|\n)([ \t]*)$/.exec(root.raws.codeBefore);

			if (match) {
				return match[1] + firstLine;
			}

			return '';
		});

		const indents = source.match(/^[ \t]*(?=\S)/gm);

		if (indents) {
			return Math.min(...indents.map((indent) => getIndentLevel(indent)));
		}

		newBaseIndentLevel = 1;
	} else {
		newBaseIndentLevel = baseIndentLevel;
	}

	const indents = [];
	const foundIndents = root.raws.codeBefore && /(?:^|\n)([ \t]*)\S/m.exec(root.raws.codeBefore);

	// The indent level of the CSS code block in non-CSS-like files is determined by the shortest indent of non-empty line.
	if (foundIndents) {
		let shortest = Number.MAX_SAFE_INTEGER;
		let i = 0;

		while (++i < foundIndents.length) {
			const current = getIndentLevel(foundIndents[i]);

			if (current < shortest) {
				shortest = current;

				if (shortest === 0) {
					break;
				}
			}
		}

		if (shortest !== Number.MAX_SAFE_INTEGER) {
			indents.push(new Array(shortest).fill(' ').join(''));
		}
	}

	const after = root.raws.after;

	if (after) {
		let afterEnd;

		if (after.endsWith('\n')) {
			// @ts-expect-error -- TS2339: Property 'document' does not exist on type 'Root'.
			const document = root.document;

			if (document) {
				const nextRoot = document.nodes[document.nodes.indexOf(root) + 1];

				afterEnd = nextRoot ? nextRoot.raws.codeBefore : document.raws.codeAfter;
			} else {
				// Nested root node in css-in-js lang
				const parent = root.parent;

				if (!parent) throw new Error('The root node must have a parent');

				const nextRoot = parent.nodes[parent.nodes.indexOf(root) + 1];

				afterEnd = nextRoot ? nextRoot.raws.codeBefore : root.raws.codeAfter;
			}
		} else {
			afterEnd = after;
		}

		if (afterEnd) indents.push(afterEnd.match(/^[ \t]*/)[0]);
	}

	if (indents.length) {
		return Math.max(...indents.map((indent) => getIndentLevel(indent))) + newBaseIndentLevel;
	}

	return newBaseIndentLevel;
}

/**
 * @param {string | undefined} str
 * @param {string} whitespace
 */
function fixIndentation(str, whitespace) {
	if (!isString(str)) {
		return str;
	}

	return str.replace(/\n[ \t]*(?=\S|$)/g, `\n${whitespace}`);
}

/**
 * @param {string} input
 * @param {string} searchString
 * @param {string} replaceString
 * @param {number} startIndex
 */
function replaceIndentation(input, searchString, replaceString, startIndex) {
	const offset = startIndex + 1;
	const stringStart = input.slice(0, offset);
	const stringEnd = input.slice(offset + searchString.length);

	return stringStart + replaceString + stringEnd;
}

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