"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.default = resolveDefaultsAtRules;
exports.elementSelectorParser = void 0;
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _featureFlags = require("../featureFlags");
function resolveDefaultsAtRules({ tailwindConfig  }) {
    return (root)=>{
        let variableNodeMap = new Map();
        /** @type {Set<import('postcss').AtRule>} */ let universals = new Set();
        root.walkAtRules("defaults", (rule)=>{
            if (rule.nodes && rule.nodes.length > 0) {
                universals.add(rule);
                return;
            }
            let variable = rule.params;
            if (!variableNodeMap.has(variable)) {
                variableNodeMap.set(variable, new Set());
            }
            variableNodeMap.get(variable).add(rule.parent);
            rule.remove();
        });
        for (let universal of universals){
            /** @type {Map<string, Set<string>>} */ let selectorGroups = new Map();
            var ref;
            let rules = (ref = variableNodeMap.get(universal.params)) !== null && ref !== void 0 ? ref : [];
            for (let rule of rules){
                for (let selector of extractElementSelector(rule.selector)){
                    // If selector contains a vendor prefix after a pseudo element or class,
                    // we consider them separately because merging the declarations into
                    // a single rule will cause browsers that do not understand the
                    // vendor prefix to throw out the whole rule
                    let selectorGroupName = selector.includes(":-") || selector.includes("::-") ? selector : "__DEFAULT__";
                    var ref1;
                    let selectors = (ref1 = selectorGroups.get(selectorGroupName)) !== null && ref1 !== void 0 ? ref1 : new Set();
                    selectorGroups.set(selectorGroupName, selectors);
                    selectors.add(selector);
                }
            }
            if ((0, _featureFlags).flagEnabled(tailwindConfig, "optimizeUniversalDefaults")) {
                if (selectorGroups.size === 0) {
                    universal.remove();
                    continue;
                }
                for (let [, selectors] of selectorGroups){
                    let universalRule = _postcss.default.rule({
                        source: universal.source
                    });
                    universalRule.selectors = [
                        ...selectors
                    ];
                    universalRule.append(universal.nodes.map((node)=>node.clone()
                    ));
                    universal.before(universalRule);
                }
            } else {
                let universalRule = _postcss.default.rule({
                    source: universal.source
                });
                universalRule.selectors = [
                    "*",
                    "::before",
                    "::after"
                ];
                universalRule.append(universal.nodes);
                universal.before(universalRule);
            }
            universal.remove();
        }
    };
}
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
let getNode = {
    id (node) {
        return _postcssSelectorParser.default.attribute({
            attribute: "id",
            operator: "=",
            value: node.value,
            quoteMark: '"'
        });
    }
};
function minimumImpactSelector(nodes) {
    let rest = nodes.filter((node)=>{
        // Keep non-pseudo nodes
        if (node.type !== "pseudo") return true;
        // Keep pseudo nodes that have subnodes
        // E.g.: `:not()` contains subnodes inside the parentheses
        if (node.nodes.length > 0) return true;
        // Keep pseudo `elements`
        // This implicitly means that we ignore pseudo `classes`
        return node.value.startsWith("::") || [
            ":before",
            ":after",
            ":first-line",
            ":first-letter"
        ].includes(node.value);
    }).reverse();
    let searchFor = new Set([
        "tag",
        "class",
        "id",
        "attribute"
    ]);
    let splitPointIdx = rest.findIndex((n)=>searchFor.has(n.type)
    );
    if (splitPointIdx === -1) return rest.reverse().join("").trim();
    let node1 = rest[splitPointIdx];
    let bestNode = getNode[node1.type] ? getNode[node1.type](node1) : node1;
    rest = rest.slice(0, splitPointIdx);
    let combinatorIdx = rest.findIndex((n)=>n.type === "combinator" && n.value === ">"
    );
    if (combinatorIdx !== -1) {
        rest.splice(0, combinatorIdx);
        rest.unshift(_postcssSelectorParser.default.universal());
    }
    return [
        bestNode,
        ...rest.reverse()
    ].join("").trim();
}
let elementSelectorParser = (0, _postcssSelectorParser).default((selectors)=>{
    return selectors.map((s)=>{
        let nodes = s.split((n)=>n.type === "combinator" && n.value === " "
        ).pop();
        return minimumImpactSelector(nodes);
    });
});
exports.elementSelectorParser = elementSelectorParser;
let cache = new Map();
function extractElementSelector(selector) {
    if (!cache.has(selector)) {
        cache.set(selector, elementSelectorParser.transformSync(selector));
    }
    return cache.get(selector);
}
