import cssEscape from '../shared/utils/css-escape.mjs';
import { START_SYMBOLS } from '../constants/start-symbol.mjs';
import { Layer } from '../layer.mjs';

const BORDER_STYLES = [
    'none',
    'auto',
    'hidden',
    'dotted',
    'dashed',
    'solid',
    'double',
    'groove',
    'ridge',
    'inset',
    'outset'
];
const autofillSolidToValueComponent = function(valueComponents) {
    if (valueComponents.length < 2) return valueComponents;
    const styleValueComponent = valueComponents.find((valueComponent)=>{
        return valueComponent.type === 'string' && BORDER_STYLES.includes(valueComponent.value) || valueComponent.type === 'variable' && BORDER_STYLES.includes(valueComponent.variable?.value);
    });
    if (!styleValueComponent) {
        valueComponents.push({
            type: 'separator',
            value: ' '
        }, {
            type: 'string',
            value: 'solid'
        });
    }
    return valueComponents;
};
const rules = {
    group: {
        match: /^(?:.+?[*_>~+])?\{.+?\}/,
        layer: Layer.Core,
        analyze (className) {
            let i = 0;
            for(; i < className.length; i++){
                if (className[i] === '{' && className[i - 1] !== '\\') {
                    break;
                }
            }
            return [
                className.slice(i),
                className.slice(0, i)
            ];
        },
        declare (value) {
            const declarations = {};
            const addProp = (propertyName)=>{
                const indexOfColon = propertyName.indexOf(':');
                if (indexOfColon !== -1) {
                    const propName = propertyName.slice(0, indexOfColon);
                    declarations[propName] = propertyName.slice(indexOfColon + 1);
                }
            };
            const handleRule = (rule)=>{
                const addProps = (cssText)=>{
                    const cssProperties = cssText.slice(cssEscape(rule.className).length).match(/\{(.*)\}/)?.[1].split(';');
                    if (cssProperties) for (const eachCssProperty of cssProperties){
                        addProp(eachCssProperty);
                    }
                };
                for (const eachNative of rule.natives){
                    addProps(eachNative.text);
                }
                // animation
                if (rule.animationNames) {
                    if (!this.animationNames) {
                        this.animationNames = [];
                    }
                    for (const eachKeyframeName of rule.animationNames){
                        if (!this.animationNames.includes(eachKeyframeName)) {
                            this.animationNames.push(eachKeyframeName);
                        }
                    }
                }
                // variable
                if (rule.variableNames) {
                    if (!this.variableNames) {
                        this.variableNames = [];
                    }
                    for (const eachVariableName of rule.variableNames){
                        if (!this.variableNames.includes(eachVariableName)) {
                            this.variableNames.push(eachVariableName);
                        }
                    }
                }
            };
            const names = [];
            let currentName = '';
            const addName = ()=>{
                if (currentName) {
                    names.push(currentName.replace(/ /g, '|'));
                    currentName = '';
                }
            };
            let i = 1;
            (function analyze(end) {
                for(; i < value.length; i++){
                    const char = value[i];
                    if (!end) {
                        if (char === ';') {
                            addName();
                            continue;
                        }
                        if (char === '}') {
                            break;
                        }
                    }
                    currentName += char;
                    if (end === char) {
                        if (end === '\'' || end === '"') {
                            let count = 0;
                            for(let j = currentName.length - 2;; j--){
                                if (currentName[j] !== '\\') {
                                    break;
                                }
                                count++;
                            }
                            if (count % 2) {
                                continue;
                            }
                        }
                        break;
                    } else if (char in START_SYMBOLS && end !== '\'' && end !== '"') {
                        i++;
                        analyze(START_SYMBOLS[char]);
                    }
                }
            })('');
            addName();
            for (const eachName of names){
                const rules = this.css.generate(eachName);
                if (rules.length) {
                    for (const eachRule of rules){
                        handleRule(eachRule);
                    }
                } else {
                    addProp(eachName);
                }
            }
            return declarations;
        }
    },
    variable: {
        match: /^\$[\w-]+:/,
        colored: true,
        layer: Layer.Core,
        declare (value) {
            return {
                ['--' + this.prefix.slice(1, -1)]: value
            };
        }
    },
    'font-size': {
        match: [
            'f(?:ont)?'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'font-weight': {
        match: [
            'f(?:ont)?',
            [
                'bolder'
            ]
        ],
        layer: Layer.CoreNative
    },
    'font-family': {
        match: [
            'f(?:ont)?'
        ],
        layer: Layer.CoreNative
    },
    'font-smoothing': {
        match: [
            'f(?:ont)?',
            [
                'antialiased',
                'subpixel-antialiased'
            ]
        ],
        layer: Layer.CoreNative,
        declare (value) {
            switch(value){
                case 'subpixel-antialiased':
                    return {
                        '-webkit-font-smoothing': 'auto',
                        '-moz-osx-font-smoothing': 'auto'
                    };
                case 'antialiased':
                    return {
                        '-webkit-font-smoothing': 'antialiased',
                        '-moz-osx-font-smoothing': 'grayscale'
                    };
            }
        }
    },
    'font-style': {
        match: [
            'f(?:ont)?',
            [
                'normal',
                'italic',
                'oblique'
            ]
        ],
        layer: Layer.CoreNative,
        unit: 'deg'
    },
    'font-variant-numeric': {
        match: [
            'f(?:ont)?',
            [
                'ordinal',
                'slashed-zero',
                'lining-nums',
                'oldstyle-nums',
                'proportional-nums',
                'tabular-nums',
                'diagonal-fractions',
                'stacked-fractions'
            ]
        ],
        layer: Layer.CoreNative
    },
    'font-variant': {
        layer: Layer.CoreNativeShorthand
    },
    'font-feature-settings': {
        match: /^font-feature:/,
        layer: Layer.CoreNative
    },
    font: {
        match: /^f:/,
        layer: Layer.CoreNativeShorthand,
        variables: [
            'font-family',
            'font-variant',
            'font-weight',
            'font-size',
            'font-style',
            'line-height'
        ]
    },
    color: {
        match: /^(?:color|fg):/,
        layer: Layer.CoreNative,
        colored: true,
        variables: [
            'text'
        ]
    },
    // margin
    'margin-left': {
        match: /^ml:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-right': {
        match: /^mr:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-top': {
        match: /^mt:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-bottom': {
        match: /^mb:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-x': {
        match: /^(?:mx|margin-x):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'margin-left': value,
                'margin-right': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'margin-y': {
        match: /^(?:my|margin-y):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'margin-top': value,
                'margin-bottom': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    margin: {
        match: /^m:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // margin inline
    'margin-inline-start': {
        match: /^mis:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-inline-end': {
        match: /^mie:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'margin-inline': {
        match: /^mi:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // padding
    'padding-left': {
        match: /^pl:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-right': {
        match: /^pr:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-top': {
        match: /^pt:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-bottom': {
        match: /^pb:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-x': {
        match: /^(?:px|padding-x):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'padding-left': value,
                'padding-right': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'padding-y': {
        match: /^(?:py|padding-y):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'padding-top': value,
                'padding-bottom': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    padding: {
        match: /^p:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // padding inline
    'padding-inline-start': {
        match: /^pis:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-inline-end': {
        match: /^pie:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'padding-inline': {
        match: /^pi:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // flex
    'flex-basis': {
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'flex-wrap': {
        match: [
            'flex',
            [
                'wrap',
                'nowrap',
                'wrap-reverse'
            ]
        ],
        layer: Layer.CoreNative
    },
    'flex-grow': {
        layer: Layer.CoreNative
    },
    'flex-shrink': {
        layer: Layer.CoreNative
    },
    'flex-direction': {
        match: [
            'flex',
            [
                'row',
                'row-reverse',
                'column',
                'column-reverse'
            ]
        ],
        layer: Layer.CoreNative
    },
    flex: {
        layer: Layer.CoreNativeShorthand
    },
    display: {
        match: /^d:/,
        layer: Layer.CoreNative
    },
    width: {
        match: /^w:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    height: {
        match: /^h:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'min-width': {
        match: /^min-w:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'min-height': {
        match: /^min-h:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    size: {
        match: /^size:/,
        layer: Layer.CoreShorthand,
        unit: 'rem',
        declare (_value, valueComponents) {
            const length = valueComponents.length;
            return {
                width: length === 1 ? valueComponents[0].text : valueComponents[0].text,
                height: length === 1 ? valueComponents[0].text : valueComponents[2].text
            };
        }
    },
    'min-size': {
        match: /^min:/,
        layer: Layer.CoreShorthand,
        unit: 'rem',
        declare (_value, valueComponents) {
            const length = valueComponents.length;
            return {
                'min-width': length === 1 ? valueComponents[0].text : valueComponents[0].text,
                'min-height': length === 1 ? valueComponents[0].text : valueComponents[2].text
            };
        }
    },
    'max-size': {
        match: /^max:/,
        layer: Layer.CoreShorthand,
        unit: 'rem',
        declare (_value, valueComponents) {
            const length = valueComponents.length;
            return {
                'max-width': length === 1 ? valueComponents[0].text : valueComponents[0].text,
                'max-height': length === 1 ? valueComponents[0].text : valueComponents[2].text
            };
        }
    },
    'box-sizing': {
        match: /^box:/,
        layer: Layer.CoreNative
    },
    'box-decoration-break': {
        match: [
            'box-decoration',
            [
                'slice',
                'clone'
            ]
        ],
        layer: Layer.CoreNative,
        declare (value) {
            return {
                'box-decoration-break': value,
                '-webkit-box-decoration-break': value
            };
        }
    },
    contain: {
        layer: Layer.CoreNative
    },
    content: {
        layer: Layer.CoreNative
    },
    'counter-increment': {
        layer: Layer.CoreNative
    },
    'counter-reset': {
        layer: Layer.CoreNative
    },
    'letter-spacing': {
        match: /^ls:/,
        layer: Layer.CoreNative,
        unit: 'em'
    },
    'line-height': {
        match: /^lh:/,
        layer: Layer.CoreNative
    },
    'object-fit': {
        match: [
            '(?:object|obj)',
            [
                'contain',
                'cover',
                'fill',
                'scale-down'
            ]
        ],
        layer: Layer.CoreNative
    },
    'object-position': {
        match: [
            '(?:object|obj)',
            [
                'top',
                'bottom',
                'right',
                'left',
                'center'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-align': {
        match: [
            't(?:ext)?',
            [
                'justify',
                'center',
                'left',
                'right',
                'start',
                'end'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-decoration-color': {
        match: [
            'text-decoration'
        ],
        layer: Layer.CoreNative,
        colored: true,
        variables: [
            'text'
        ]
    },
    'text-decoration-style': {
        match: [
            't(?:ext)?',
            [
                'solid',
                'double',
                'dotted',
                'dashed',
                'wavy'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-decoration-thickness': {
        match: [
            'text-decoration',
            [
                'from-font'
            ]
        ],
        numeric: true,
        layer: Layer.CoreNative,
        unit: 'em'
    },
    'text-decoration-line': {
        match: [
            't(?:ext)?',
            [
                'none',
                'underline',
                'overline',
                'line-through'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-decoration': {
        match: [
            't(?:ext)?',
            [
                'underline',
                'overline',
                'line-through'
            ]
        ],
        unit: 'rem',
        colored: true,
        layer: Layer.CoreNativeShorthand,
        variables: [
            'text'
        ]
    },
    'text-underline-offset': {
        unit: 'rem',
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    'text-overflow': {
        match: [
            't(?:ext)?',
            [
                'ellipsis',
                'clip'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-orientation': {
        match: [
            't(?:ext)?',
            [
                'mixed',
                'upright',
                'sideways-right',
                'sideways',
                'use-glyph-orientation'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-transform': {
        match: [
            't(?:ext)?',
            [
                'uppercase',
                'lowercase',
                'capitalize'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-rendering': {
        match: [
            't(?:ext)?',
            [
                'optimizeSpeed',
                'optimizeLegibility',
                'geometricPrecision'
            ]
        ],
        layer: Layer.CoreNative
    },
    'text-indent': {
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'vertical-align': {
        match: /^(?:v|vertical):/,
        layer: Layer.CoreNative
    },
    columns: {
        match: /^(?:columns|cols):/,
        layer: Layer.CoreNativeShorthand
    },
    'white-space': {
        layer: Layer.CoreNative
    },
    top: {
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    bottom: {
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    left: {
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    right: {
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    inset: {
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    lines: {
        match: /^lines:/,
        declare (value) {
            return {
                overflow: 'hidden',
                display: '-webkit-box',
                'overflow-wrap': 'break-word',
                'text-overflow': 'ellipsis',
                '-webkit-box-orient': 'vertical',
                '-webkit-line-clamp': value
            };
        }
    },
    'max-height': {
        match: /^max-h:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'max-width': {
        match: /^max-w:/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    opacity: {
        layer: Layer.CoreNative
    },
    visibility: {
        layer: Layer.CoreNative
    },
    clear: {
        layer: Layer.CoreNative
    },
    float: {
        layer: Layer.CoreNative
    },
    isolation: {
        layer: Layer.CoreNative
    },
    'overflow-x': {
        layer: Layer.CoreNative,
        declare (value) {
            return value === 'overlay' ? {
                'overflow-x': [
                    'auto',
                    value
                ]
            } : {
                'overflow-x': value
            };
        }
    },
    'overflow-y': {
        layer: Layer.CoreNative,
        declare (value) {
            return value === 'overlay' ? {
                'overflow-y': [
                    'auto',
                    value
                ]
            } : {
                'overflow-y': value
            };
        }
    },
    overflow: {
        layer: Layer.CoreNativeShorthand,
        declare (value) {
            return value === 'overlay' ? {
                overflow: [
                    'auto',
                    value
                ]
            } : {
                overflow: value
            };
        }
    },
    'overscroll-behavior-x': {
        layer: Layer.CoreNative
    },
    'overscroll-behavior-y': {
        layer: Layer.CoreNative
    },
    'overscroll-behavior': {
        layer: Layer.CoreNativeShorthand
    },
    'z-index': {
        match: /^z:/,
        layer: Layer.CoreNative
    },
    position: {
        layer: Layer.CoreNative
    },
    cursor: {
        layer: Layer.CoreNative
    },
    'pointer-events': {
        layer: Layer.CoreNative
    },
    resize: {
        layer: Layer.CoreNative
    },
    'touch-action': {
        layer: Layer.CoreNative
    },
    'word-break': {
        layer: Layer.CoreNative
    },
    'word-spacing': {
        layer: Layer.CoreNative,
        unit: 'em'
    },
    'user-drag': {
        layer: Layer.CoreNative,
        declare (value) {
            return {
                'user-drag': value,
                '-webkit-user-drag': value
            };
        }
    },
    'user-select': {
        layer: Layer.CoreNative,
        declare (value) {
            return {
                'user-select': value,
                '-webkit-user-select': value
            };
        }
    },
    'text-shadow': {
        unit: 'rem',
        layer: Layer.CoreNative,
        colored: true
    },
    'text-size': {
        match: [
            't(?:ext)?'
        ],
        numeric: true,
        unit: 'rem',
        declare (value) {
            const diff = .875;
            return {
                'font-size': value,
                'line-height': `calc(${value} + ${diff}em)`
            };
        }
    },
    'text-fill-color': {
        match: [
            '(?:text-fill|text|t)'
        ],
        layer: Layer.CoreNative,
        colored: true,
        variables: [
            'text'
        ],
        declare (value) {
            return {
                '-webkit-text-fill-color': value
            };
        }
    },
    'text-stroke-width': {
        match: [
            'text-stroke',
            [
                'thin',
                'medium',
                'thick'
            ]
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative,
        declare (value) {
            return {
                '-webkit-text-stroke-width': value
            };
        }
    },
    'text-stroke-color': {
        match: [
            'text-stroke'
        ],
        layer: Layer.CoreNative,
        colored: true,
        variables: [
            'text'
        ],
        declare (value) {
            return {
                '-webkit-text-stroke-color': value
            };
        }
    },
    'text-stroke': {
        unit: 'rem',
        layer: Layer.CoreNative,
        declare (value) {
            return {
                '-webkit-text-stroke': value
            };
        }
    },
    'box-shadow': {
        match: /^s(?:hadow)?:/,
        unit: 'rem',
        layer: Layer.CoreNative,
        colored: true
    },
    'table-layout': {
        layer: Layer.CoreNative
    },
    'transform-box': {
        match: [
            'transform'
        ],
        layer: Layer.CoreNative
    },
    'transform-style': {
        match: [
            'transform',
            [
                'flat',
                'preserve-3d'
            ]
        ],
        layer: Layer.CoreNative
    },
    'transform-origin': {
        match: [
            'transform',
            [
                'top',
                'bottom',
                'right',
                'left',
                'center'
            ]
        ],
        numeric: true,
        unit: 'px',
        layer: Layer.CoreNative
    },
    transform: {
        match: /^(?:translate|scale|skew|rotate|perspective|matrix)(?:3d|[XYZ])?\(/,
        layer: Layer.CoreNative,
        analyze (className) {
            return [
                className.startsWith('transform') ? className.slice(10) : className
            ];
        },
        variables: [
            'spacing'
        ]
    },
    'transition-property': {
        match: /^~property:/,
        layer: Layer.CoreNative
    },
    'transition-timing-function': {
        match: /^~easing:/,
        layer: Layer.CoreNative
    },
    'transition-duration': {
        match: /^~duration:/,
        layer: Layer.CoreNative,
        unit: 'ms'
    },
    'transition-delay': {
        match: /^~delay:/,
        layer: Layer.CoreNative,
        unit: 'ms'
    },
    transition: {
        match: /^~[^!*>+~:[@_]+\|/,
        analyze (className) {
            if (className.startsWith('~')) {
                return [
                    className.slice(1)
                ];
            } else {
                const indexOfColon = className.indexOf(':');
                this.prefix = className.slice(0, indexOfColon + 1);
                return [
                    className.slice(indexOfColon + 1)
                ];
            }
        },
        layer: Layer.CoreNativeShorthand
    },
    'animation-delay': {
        match: /^@delay:/,
        layer: Layer.CoreNative,
        unit: 'ms'
    },
    'animation-direction': {
        match: /^@direction:/,
        layer: Layer.CoreNative
    },
    'animation-duration': {
        match: /^@duration:/,
        layer: Layer.CoreNative,
        unit: 'ms'
    },
    'animation-fill-mode': {
        match: /^@fill:/,
        layer: Layer.CoreNative
    },
    'animation-iteration-count': {
        match: /^@iteration:/,
        layer: Layer.CoreNative
    },
    'animation-name': {
        match: /^@name:/,
        layer: Layer.CoreNative
    },
    'animation-play-state': {
        match: /^@play:/,
        layer: Layer.CoreNative
    },
    'animation-timing-function': {
        match: /^@easing:/,
        layer: Layer.CoreNative
    },
    animation: {
        match: /^@[^!*>+~:[@_]+\|/,
        layer: Layer.CoreNativeShorthand,
        analyze (className) {
            if (className.startsWith('@')) {
                return [
                    className.slice(1)
                ];
            } else {
                const indexOfColon = className.indexOf(':');
                this.prefix = className.slice(0, indexOfColon + 1);
                return [
                    className.slice(indexOfColon + 1)
                ];
            }
        }
    },
    'border-collapse': {
        match: [
            'b(?:order)?',
            [
                'collapse',
                'separate'
            ]
        ],
        layer: Layer.CoreNative
    },
    'border-spacing': {
        unit: 'rem',
        layer: Layer.CoreNative
    },
    // border color
    'border-top-color': {
        match: [
            'b(?:t|order-top(?:-color)?)'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'border-bottom-color': {
        match: [
            'b(?:b|order-bottom(?:-color)?)'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'border-left-color': {
        match: [
            'b(?:l|order-left(?:-color)?)'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'border-right-color': {
        match: [
            'b(?:r|order-right(?:-color)?)'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'border-x-color': {
        match: [
            'b(?:x|order-x(?:-color)?)'
        ],
        layer: Layer.CoreShorthand,
        colored: true,
        declare (value) {
            return {
                'border-left-color': value,
                'border-right-color': value
            };
        }
    },
    'border-y-color': {
        match: [
            'b(?:y|order-y(?:-color)?)'
        ],
        layer: Layer.CoreShorthand,
        colored: true,
        declare (value) {
            return {
                'border-top-color': value,
                'border-bottom-color': value
            };
        }
    },
    'border-color': {
        match: [
            'b(?:order)?(?:-color)?'
        ],
        layer: Layer.CoreNativeShorthand,
        colored: true
    },
    // border radius
    'border-top-left-radius': {
        match: /^r(?:tl|lt):/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-top-right-radius': {
        match: /^r(?:tr|rt):/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-bottom-left-radius': {
        match: /^r(?:bl|lb):/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-bottom-right-radius': {
        match: /^r(?:br|rb):/,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-top-radius': {
        match: /^rt:/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-top-left-radius': value,
                'border-top-right-radius': value
            };
        }
    },
    'border-bottom-radius': {
        match: /^rb:/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-bottom-left-radius': value,
                'border-bottom-right-radius': value
            };
        }
    },
    'border-left-radius': {
        match: /^rl:/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-top-left-radius': value,
                'border-bottom-left-radius': value
            };
        }
    },
    'border-right-radius': {
        match: /^rr:/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-top-right-radius': value,
                'border-bottom-right-radius': value
            };
        }
    },
    'border-radius': {
        match: /^r:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand
    },
    // border style
    'border-top-style': {
        match: [
            'b(?:t|order-top(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreNative
    },
    'border-bottom-style': {
        match: [
            'b(?:b|order-bottom(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreNative
    },
    'border-left-style': {
        match: [
            'b(?:l|order-left(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreNative
    },
    'border-right-style': {
        match: [
            'b(?:r|order-right(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreNative
    },
    'border-x-style': {
        match: [
            'b(?:x|order-x(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-left-style': value,
                'border-right-style': value
            };
        }
    },
    'border-y-style': {
        match: [
            'b(?:y|order-y(?:-style)?)',
            BORDER_STYLES
        ],
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-top-style': value,
                'border-bottom-style': value
            };
        }
    },
    'border-style': {
        match: [
            'b(?:order)?(?:-style)?',
            BORDER_STYLES
        ],
        layer: Layer.CoreNativeShorthand
    },
    // border width
    'border-top-width': {
        match: [
            'b(?:t|order-top(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-bottom-width': {
        match: [
            'b(?:b|order-bottom(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-left-width': {
        match: [
            'b(?:l|order-left(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-right-width': {
        match: [
            'b(?:r|order-right(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-x-width': {
        match: [
            'b(?:x|order-x(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-left-width': value,
                'border-right-width': value
            };
        }
    },
    'border-y-width': {
        match: [
            'b(?:y|order-y(?:-width)?)'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'border-top-width': value,
                'border-bottom-width': value
            };
        }
    },
    'border-width': {
        match: [
            'b(?:order)?(?:-width)?'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand
    },
    // border image
    'border-image-outset': {
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-image-repeat': {
        match: [
            'border-image',
            [
                'stretch',
                'repeat',
                'round',
                'space'
            ]
        ],
        layer: Layer.CoreNative
    },
    'border-image-slice': {
        layer: Layer.CoreNative
    },
    'border-image-source': {
        match: [
            'border-image',
            [
                'url',
                'linear-gradient',
                'radial-gradient',
                'repeating-linear-gradient',
                'repeating-radial-gradient',
                'conic-gradient'
            ]
        ],
        layer: Layer.CoreNative
    },
    'border-image-width': {
        match: [
            'border-image',
            [
                'auto'
            ]
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'border-image': {
        layer: Layer.CoreNativeShorthand
    },
    // border
    'border-top': {
        match: /^bt:/,
        layer: Layer.CoreNativeShorthand,
        unit: 'rem',
        colored: true,
        transformValueComponents: autofillSolidToValueComponent
    },
    'border-bottom': {
        match: /^bb:/,
        layer: Layer.CoreNativeShorthand,
        unit: 'rem',
        colored: true,
        transformValueComponents: autofillSolidToValueComponent
    },
    'border-left': {
        match: /^bl:/,
        layer: Layer.CoreNativeShorthand,
        unit: 'rem',
        colored: true,
        transformValueComponents: autofillSolidToValueComponent
    },
    'border-right': {
        match: /^br:/,
        layer: Layer.CoreNativeShorthand,
        unit: 'rem',
        colored: true,
        transformValueComponents: autofillSolidToValueComponent
    },
    'border-x': {
        match: /^(?:bx|border-x):/,
        unit: 'rem',
        colored: true,
        layer: Layer.CoreShorthand,
        transformValueComponents: autofillSolidToValueComponent,
        declare (value) {
            return {
                'border-left': value,
                'border-right': value
            };
        }
    },
    'border-y': {
        match: /^(?:by|border-y):/,
        unit: 'rem',
        colored: true,
        layer: Layer.CoreShorthand,
        transformValueComponents: autofillSolidToValueComponent,
        declare (value) {
            return {
                'border-top': value,
                'border-bottom': value
            };
        }
    },
    border: {
        match: /^b:/,
        unit: 'rem',
        colored: true,
        layer: Layer.CoreNativeShorthand,
        transformValueComponents: autofillSolidToValueComponent
    },
    'background-attachment': {
        match: [
            '(?:bg|background)',
            [
                'fixed',
                'local',
                'scroll'
            ]
        ],
        layer: Layer.CoreNative
    },
    'background-blend-mode': {
        layer: Layer.CoreNative
    },
    'background-color': {
        match: [
            '(?:bg|background)'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'background-clip': {
        match: [
            '(?:bg|background)',
            [
                'text'
            ]
        ],
        layer: Layer.CoreNative,
        declare (value) {
            return {
                '-webkit-background-clip': value,
                'background-clip': value
            };
        }
    },
    'background-origin': {
        match: [
            '(?:bg|background)'
        ],
        layer: Layer.CoreNative
    },
    'background-position': {
        match: [
            '(?:bg|background)',
            [
                'top',
                'bottom',
                'right',
                'left',
                'center'
            ]
        ],
        layer: Layer.CoreNative,
        unit: 'px'
    },
    'background-repeat': {
        match: [
            '(?:bg|background)',
            [
                'space',
                'round',
                'repeat',
                'no-repeat',
                'repeat-x',
                'repeat-y'
            ]
        ],
        layer: Layer.CoreNative
    },
    'background-size': {
        match: [
            '(?:bg|background)',
            [
                'auto',
                'cover',
                'contain'
            ]
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    'background-image': {
        match: [
            '(?:bg|background)',
            [
                '(?:url|linear-gradient|radial-gradient|repeating-linear-gradient|repeating-radial-gradient|conic-gradient)\\(.*\\)'
            ]
        ],
        layer: Layer.CoreNative
    },
    background: {
        match: /^bg:/,
        colored: true,
        layer: Layer.CoreNativeShorthand
    },
    gradient: {
        match: /^gradient\(/,
        layer: Layer.CoreNative,
        colored: true,
        declare (value) {
            return {
                'background-image': 'linear-' + value
            };
        }
    },
    'mix-blend-mode': {
        match: /^blend:/,
        layer: Layer.CoreNative
    },
    'backdrop-filter': {
        match: /^bd:/,
        layer: Layer.CoreNative,
        colored: true,
        declare (value) {
            return {
                'backdrop-filter': value,
                '-webkit-backdrop-filter': value
            };
        }
    },
    filter: {
        match: /^(?:blur|brightness|contrast|drop-shadow|grayscale|hue-rotate|invert|opacity|saturate|sepia)\(/,
        layer: Layer.CoreNative,
        colored: true
    },
    fill: {
        match: /^fill:/,
        layer: Layer.CoreNative,
        colored: true
    },
    'stroke-dasharray': {
        layer: Layer.CoreNative
    },
    'stroke-dashoffset': {
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    'stroke-width': {
        match: [
            'stroke(?:-width)?'
        ],
        numeric: true,
        layer: Layer.CoreNative
    },
    stroke: {
        match: [
            'stroke'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    x: {
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    y: {
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    cx: {
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    cy: {
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    rx: {
        layer: Layer.CoreNative
    },
    ry: {
        layer: Layer.CoreNative
    },
    'grid-column-start': {
        match: /^grid-col(?:umn)?-start:/,
        layer: Layer.CoreNative
    },
    'grid-column-end': {
        match: /^grid-col(?:umn)?-end:/,
        layer: Layer.CoreNative
    },
    'grid-column': {
        match: /^grid-col(?:umn)?(?:-span)?:/,
        layer: Layer.CoreNativeShorthand,
        transformValue (value) {
            return this.prefix.slice(-5, -1) === 'span' && value !== 'auto' ? 'span' + ' ' + value + '/' + 'span' + ' ' + value : value;
        }
    },
    'grid-columns': {
        match: /^grid-col(?:umn)?s:/,
        declare (value) {
            return {
                display: 'grid',
                'grid-template-columns': 'repeat' + '(' + value + ',' + 'minmax' + '(' + 0 + ',' + 1 + 'fr' + '))'
            };
        },
        layer: Layer.Core
    },
    'grid-row-start': {
        layer: Layer.CoreNative
    },
    'grid-row-end': {
        layer: Layer.CoreNative
    },
    'grid-row': {
        match: /^grid-row-span:/,
        layer: Layer.CoreNativeShorthand,
        transformValue (value) {
            return this.prefix.slice(-5, -1) === 'span' && value !== 'auto' ? 'span' + ' ' + value + '/' + 'span' + ' ' + value : value;
        }
    },
    'grid-rows': {
        match: /^grid-rows:/,
        declare (value) {
            return {
                display: 'grid',
                'grid-auto-flow': 'column',
                'grid-template-rows': 'repeat' + '(' + value + ',' + 'minmax' + '(' + 0 + ',' + 1 + 'fr' + '))'
            };
        },
        layer: Layer.Core
    },
    'grid-auto-columns': {
        match: /^grid-auto-cols:/,
        layer: Layer.CoreNative
    },
    'grid-auto-flow': {
        match: /^grid-flow:/,
        layer: Layer.CoreNative
    },
    'grid-auto-rows': {
        layer: Layer.CoreNative
    },
    'grid-template-areas': {
        layer: Layer.CoreNative
    },
    'grid-template-columns': {
        match: /^grid-template-cols:/,
        layer: Layer.CoreNative,
        unit: 'rem'
    },
    'grid-template-rows': {
        layer: Layer.CoreNative,
        unit: 'rem'
    },
    'grid-template': {
        layer: Layer.CoreNativeShorthand
    },
    'grid-area': {
        layer: Layer.CoreNativeShorthand
    },
    grid: {
        layer: Layer.CoreNativeShorthand
    },
    'column-gap': {
        match: /^gap-x:/,
        unit: 'rem',
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    'row-gap': {
        match: /^gap-y:/,
        unit: 'rem',
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    gap: {
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    order: {
        match: /^o:/,
        layer: Layer.CoreNative
    },
    'break-inside': {
        layer: Layer.CoreNative
    },
    'break-before': {
        layer: Layer.CoreNative
    },
    'break-after': {
        layer: Layer.CoreNative
    },
    'aspect-ratio': {
        match: /^aspect:/,
        layer: Layer.CoreNative
    },
    'column-span': {
        match: /^col-span:/,
        layer: Layer.CoreNative
    },
    'align-content': {
        match: /^ac:/,
        layer: Layer.CoreNative
    },
    'align-items': {
        match: /^ai:/,
        layer: Layer.CoreNative
    },
    'align-self': {
        match: /^as:/,
        layer: Layer.CoreNative
    },
    'justify-content': {
        match: /^jc:/,
        layer: Layer.CoreNative
    },
    'justify-items': {
        match: /^ji:/,
        layer: Layer.CoreNative
    },
    'justify-self': {
        match: /^js:/,
        layer: Layer.CoreNative
    },
    'place-content': {
        layer: Layer.CoreNativeShorthand
    },
    'place-items': {
        layer: Layer.CoreNativeShorthand
    },
    'place-self': {
        layer: Layer.CoreNativeShorthand
    },
    'list-style-position': {
        match: [
            'list-style',
            [
                'inside',
                'outside'
            ]
        ],
        layer: Layer.CoreNative
    },
    'list-style-type': {
        match: [
            'list-style',
            [
                'disc',
                'decimal'
            ]
        ],
        layer: Layer.CoreNative
    },
    'list-style-image': {
        match: [
            'list-style',
            [
                '(?:url|linear-gradient|radial-gradient|repeating-linear-gradient|repeating-radial-gradient|conic-gradient)\\(.*\\)'
            ]
        ],
        layer: Layer.CoreNative
    },
    'list-style': {
        layer: Layer.CoreNativeShorthand
    },
    'outline-color': {
        match: [
            'outline'
        ],
        layer: Layer.CoreNative,
        colored: true
    },
    'outline-offset': {
        unit: 'rem',
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    'outline-style': {
        match: [
            'outline',
            BORDER_STYLES
        ],
        layer: Layer.CoreNative
    },
    'outline-width': {
        match: [
            'outline',
            [
                'medium',
                'thick',
                'thin'
            ]
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative
    },
    outline: {
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        colored: true,
        variables: [
            'outline-width',
            'outline-style',
            'outline-offset',
            'outline-color'
        ],
        transformValueComponents: autofillSolidToValueComponent
    },
    'accent-color': {
        match: /^accent:/,
        layer: Layer.CoreNative,
        colored: true
    },
    appearance: {
        layer: Layer.CoreNative
    },
    'caret-color': {
        match: /^caret:/,
        layer: Layer.CoreNative,
        colored: true,
        variables: [
            'text'
        ]
    },
    'scroll-behavior': {
        layer: Layer.CoreNative
    },
    // scroll margin
    'scroll-margin-left': {
        match: /^scroll-ml:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-margin-right': {
        match: /^scroll-mr:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-margin-top': {
        match: /^scroll-mt:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-margin-bottom': {
        match: /^scroll-mb:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-margin-x': {
        match: /^(?:scroll-margin-x|scroll-mx):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'scroll-margin-left': value,
                'scroll-margin-right': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'scroll-margin-y': {
        match: /^(?:scroll-margin-y|scroll-my):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'scroll-margin-top': value,
                'scroll-margin-bottom': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'scroll-margin': {
        match: /^scroll-m:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // scroll padding
    'scroll-padding-left': {
        match: /^scroll-pl:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-padding-right': {
        match: /^scroll-pr:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-padding-top': {
        match: /^scroll-pt:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-padding-bottom': {
        match: /^scroll-pb:/,
        layer: Layer.CoreNative,
        unit: 'rem',
        variables: [
            'spacing'
        ]
    },
    'scroll-padding-x': {
        match: /^(?:scroll-padding-x|scroll-px):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'scroll-padding-left': value,
                'scroll-padding-right': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'scroll-padding-y': {
        match: /^(?:scroll-padding-y|scroll-py):/,
        unit: 'rem',
        layer: Layer.CoreShorthand,
        declare (value) {
            return {
                'scroll-padding-top': value,
                'scroll-padding-bottom': value
            };
        },
        variables: [
            'spacing'
        ]
    },
    'scroll-padding': {
        match: /^scroll-p:/,
        unit: 'rem',
        layer: Layer.CoreNativeShorthand,
        variables: [
            'spacing'
        ]
    },
    // scroll snap
    'scroll-snap-align': {
        match: [
            'scroll-snap',
            [
                'start',
                'end',
                'center'
            ]
        ],
        layer: Layer.CoreNative
    },
    'scroll-snap-stop': {
        match: [
            'scroll-snap',
            [
                'normal',
                'always'
            ]
        ],
        layer: Layer.CoreNative
    },
    'scroll-snap-type': {
        match: [
            'scroll-snap',
            [
                'x',
                'y',
                'block',
                'inline',
                'both'
            ]
        ],
        layer: Layer.CoreNative
    },
    'will-change': {
        layer: Layer.CoreNative
    },
    'writing-mode': {
        match: /^writing:/,
        layer: Layer.CoreNative
    },
    direction: {
        layer: Layer.CoreNative
    },
    'shape-outside': {
        match: [
            'shape',
            [
                '(?:inset|circle|ellipse|polygon|url|linear-gradient)\\(.*\\)'
            ]
        ],
        layer: Layer.CoreNative
    },
    'shape-margin': {
        match: [
            'shape'
        ],
        numeric: true,
        unit: 'rem',
        layer: Layer.CoreNative,
        variables: [
            'spacing'
        ]
    },
    'shape-image-threshold': {
        layer: Layer.CoreNative
    },
    'clip-path': {
        match: /^clip:/,
        layer: Layer.CoreNative
    },
    quotes: {
        layer: Layer.CoreNative
    },
    'mask-image': {
        layer: Layer.CoreNative,
        declare (value) {
            return {
                'mask-image': value,
                '-webkit-mask-image': value
            };
        }
    }
};

export { BORDER_STYLES, autofillSolidToValueComponent, rules as default };
