import fs from 'fs';
import path from 'path';



/**
 * Contains args of the program.
 * @type {Array}
 */
const ARGS = process.argv.slice(2);

/**
 * Get a specific arg by his name.
 * @param {string} name
 * @param {*} fallback
 * @return {*}
 */
function getArg(name, fallback) {
    const index = ARGS.indexOf(`--${name}`);
    return index !== -1 ? ARGS[index + 1] : fallback;
}

const PREFIX = getArg('prefix', '\\$' );
const INPUT_DIRS = getArg('input', './resources/css').split(',');
const OUTPUT_FILE = getArg('output',  './extra.less');
const EXCLUDE = getArg('exclude', '*.min.css,app.css').split(',');

/**
 * Recursively collect CSS files in a folder.
 * @param {string} dir
 * @returns {string[]}
 */
function getCssFiles(dir){
    if(!fs.existsSync(dir))
        return [];

    const RESULTS = [];
    for( const ENTRY of fs.readdirSync(dir, { withFileTypes: true }) ){
        const PATH = path.join(dir, ENTRY.name);
        if(ENTRY.isDirectory()){
            RESULTS.push(...getCssFiles(PATH));
        } else if( ENTRY.isFile() && ENTRY.name.endsWith('.css')){
            const ENT_EXCLUDE = EXCLUDE.some(pattern => {
                const re = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
                return re.test(ENTRY.name);
            });
            if (!ENT_EXCLUDE)
                RESULTS.push(PATH);
        }
    }
    return RESULTS;
}

/**
 * @param {string} part
 * @param {string} prefix
 * @return {string}
 */
function prefixSelectorPart(part, prefix){
    return part.replace(
        /(?<![#\w])\.(-?[a-zA-Z_][a-zA-Z0-9_-]*)/g,
        (match, className) => `.${prefix}${className}`
    );
}

/**
 * Prefix all classes.
 * @param {string} selector
 * @param {string} prefix
 * @returns {string}
 */
function prefixClasses(selector, prefix){
    return selector.split(',').map(part => prefixSelectorPart(part.trim(), prefix)).join(', ');
}

function css( css, prefix ){

    const LINES = css.split('\n');
    const OUT = [];

    let inKeyFrames = false;
    let braceDepth = 0;
    let pendingSelector = '';

    for(let i = 0; i < LINES.length; i++){
        const LINE = LINES[i];
        const L = LINE.trim();

        if( L === '' || L.startsWith('//') || L.startsWith('*') ){
            OUT.push(LINE);
            continue;
        }

        if( L.startsWith('@import') || L.startsWith('@source') || L.startsWith('@theme') ) // Ignore imports.
            continue;

        if( L.match(/^@keyframes\s/) ){
            inKeyFrames = true;
            OUT.push(LINE);
            continue;
        }

        if( inKeyFrames ){

            const OPEN_COUNT = (LINE.match(/\{/g) || []).length;
            const CLOSE_COUNT = (LINE.match(/\}/g) || []).length;

            OUT.push(LINE);
            braceDepth += OPEN_COUNT - CLOSE_COUNT;
            if( braceDepth <= 0 ){
                inKeyFrames = false;
                braceDepth = 0;
            }
        }

        if(L.startsWith('@media') || L.startsWith('@supports') || L.startsWith('@layer')){
            OUT.push(LINE);
            continue;
        }

        if( L.endsWith('{') ){
            const SELECTOR = L.slice(0,-1).trim();
            if( SELECTOR.startsWith('@')){
                OUT.push(SELECTOR);
                continue;
            }

            const PREFIXED = prefixClasses(SELECTOR,prefix);
            OUT.push(LINE.replace(SELECTOR,PREFIXED));
            continue;
        }

        OUT.push(LINE);
    }

    return OUT.join('\n');

}

console.log(`CSS → XenForo extra.less`);
console.log(`Prefix  : .${PREFIX}`);
console.log(`Sources : ${INPUT_DIRS.join(', ')}`);
console.log(`Output  : ${OUTPUT_FILE}\n`);

const FILES = INPUT_DIRS.flatMap(dir => getCssFiles(dir.trim()));

if (FILES.length === 0) {
    console.error( "No files found in this directory.");
    process.exit(1);
}

console.log( `${FILES.length} files found: ` );
FILES.forEach(f => console.log(` - ${f}`));

const PARTS = [];

for( const F of FILES){
    const REL_PATH = path.relative(process.cwd(), F);
    const CONTENT = fs.readFileSync(F, 'utf-8');
    const NEW = css(CONTENT, PREFIX);

    PARTS.push(`/* File: ${REL_PATH} */`);
    PARTS.push(NEW);
    PARTS.push('');
}

const FINAL = PARTS.join('\n');
fs.mkdirSync(path.dirname(OUTPUT_FILE), { recursive: true });
fs.writeFileSync(OUTPUT_FILE, FINAL, 'utf-8');

console.log( `File generated: ${OUTPUT_FILE}.`);
