function clearObject(obj) {
    for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            delete obj[key];
        }
    }
}

function extractLineFromRawText(rawText, identifier) {
    return rawText.trim().split(/\r?\n/).find(line => line.startsWith(identifier));
}

function generateUniqueId() {
    return `${Date.now()}-${Math.random().toString(36)}`;
}

function generateStyleSelector(element) {
    const prefix = ".vitara-theme-custom";
    const selectors = JSON.parse(element.getAttribute("data-css-selectors"));
    const chartName = element.getAttribute("data-chart-name");
    chartName ? selectors.unshift(chartName, prefix) : selectors.unshift(prefix);
    return selectors.join(" ");
}

function generateFontFamilyString(fonts, defaultFont = null, highPriority = true) {
    const genericFontFamilies = ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui"];
    fonts.sort((a, b) => {
        // Move default font to the start of list
        if (a === defaultFont) return -1;
        if (b === defaultFont) return 1;

        // Move generic fonts to the end of list
        const aIsGeneric = genericFontFamilies.includes(a);
        const bIsGeneric = genericFontFamilies.includes(b);
        if (aIsGeneric && !bIsGeneric) return 1;
        if (!aIsGeneric && bIsGeneric) return -1;
        
        // Keep other fonts in original order
        return 0;
    });

    const fontString = `${fonts.map(font => {
        if (genericFontFamilies.includes(font)) {
            return font; // If the font is a generic family, return it as is
        } else {
            return `'${font}'`; // If the font is a custom font, wrap it in quotes
        }
    }).join(", ")}`;

    if (highPriority) {
        return `${fontString} !important`;
    } else {
        return fontString;
    }
}

function rgbToHex(rgb) {
    const result = rgb.match(/\d+/g);
    return `#${result.map(x => {
        const hex = parseInt(x).toString(16);
        return hex.length === 1 ? '0' + hex : hex;
    }).join('').toUpperCase()}`;
}

function convertToHex(color) {
    if (!color) return null;
    const temporaryElement = document.createElement("div");
    temporaryElement.setAttribute("style", `color: ${color}; display: none;`);
    document.body.appendChild(temporaryElement);
    const computedColor = getComputedStyle(temporaryElement).color;
    document.body.removeChild(temporaryElement);
    return rgbToHex(computedColor);
}

function removeChildElements(container, count = 0) {
    while (container.childElementCount > count) {
        container.lastElementChild.remove();
    }
}

function stripQuotes(str) {
    if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
        return str.slice(1, -1);
    }
    return str;
}

function decodeHtmlEntities(str) {
    const textArea = document.createElement("textarea");
    textArea.innerHTML = str;
    return textArea.value;
}

function difference(setA, setB) {
    const result = new Set();
    for (const item of setA) {
        if (!setB.has(item)) result.add(item);
    }
    return result;
}

async function checkFileExists(url) {
    try {
        const response = await fetch(url);
        return response.ok;
    } catch (error) {
        return false;
    }
}

function getRandomColor() {
    const randomColor = Math.floor(Math.random() * 0xffffff).toString(16);
    return `#${randomColor.padStart(6, '0')}`;
}

// function cleanAndFlattenCSS(cssText) {
//     const noComments = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
//     const blocks = [...noComments.matchAll(/([^{]+)\{([^}]+)\}/g)];
//     const cleaned = blocks.map(match => {
//         const selector = match[1].replace(/\s+/g, ' ').trim();
//         const properties = match[2].replace(/\s+/g, ' ').trim();
//         return `${selector} { ${properties} }`;
//     });
//     return cleaned.join('\n');
// }

function cleanAndFlattenCSS(cssText) {
    if (!cssText || typeof cssText !== 'string') return '';
    // 1) Remove block comments (this is fine)
    let css = cssText.replace(/\/\*[\s\S]*?\*\//g, '');
    // 2) Remove dangerous at-rules (avoid [\s\S]*? which can backtrack)
    //      Match either a semicolon-terminated at-rule or a single-level block (no nested parsing).
    css = css.replace(
      /@(?:import|font-face|keyframes|media|supports|layer)\b(?:[^;{]*;|{[^}]*})/gi,
      ''
    );
    // 3) Remove url(...) occurrences — avoid [\s\S]*? and backreferences that expand wildly
    // css = css.replace(/url\(\s*(['"])?[^'")]*\1\s*\)/gi, '');
    // 4) Remove dangerous tokens (simple word/colon checks, safe and linear)
    css = css.replace(/\bjavascript\s*:/gi, '');
    css = css.replace(/\bdata\s*:/gi, '');
    css = css.replace(/\bexpression\s*\(/gi, '');
    // normalize newlines (harmless)
    css = css.replace(/\r\n|\r/g, '\n');
    // 5) Extract top-level selector { props } blocks using an exec loop and non-backtracking patterns.
    //      Use [^{]+ to read selector up to the first '{' and [^}]* for the properties block.
    const blockRegex = /([^{]+)\{([^}]*)\}/g;
    const blocks = [];
    let m;
    while ((m = blockRegex.exec(css)) !== null) {
        let selector = m[1].trim();
        if (!selector) continue;
        let props = m[2].replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim();
        // extra safety: strip leftover javascript/data/expression tokens inside the block
        props = props.replace(/\bjavascript\s*:/gi, '')
                        .replace(/\bdata\s*:/gi, '')
                        .replace(/\bexpression\s*\(/gi, '');
        // remove obviously-unsafe properties (simple conservative filter)
        props = props.replace(/(?:behavior|-\w+-binding)\s*:[^;]+;?/gi, '');
        if (props && !/;\s*$/.test(props)) props += ';';
        blocks.push(`${selector} { ${props} }`);
    }
    return blocks.join('\n').trim();
}

function parseCssBlock(cssString) {
    const properties = cssString.split(';').filter(Boolean);
    const styleObj = {};

    for (let prop of properties) {
        const [key, ...valParts] = prop.split(':');
        if (!key || !valParts.length) continue;

        const property = key.trim();
        const value = valParts.join(':').trim();
        styleObj[property] = value;
    }
    return styleObj;
}

function stringifyCssBlock(styleObj) {
    return Object.entries(styleObj)
        .map(([key, value]) => `${key}: ${value};`)
        .join(' ');
}

function checkNameValidity(name, existingNames, currentName) {
    const trimmed = name.trim();
    if (trimmed === "") {
        return { valid: false, reason: "Name cannot be empty" };
    }

    const validNameRegex = /^[a-zA-Z0-9_-]+$/;
    if (!validNameRegex.test(trimmed) || trimmed.includes("'") || trimmed.includes("\\")) {
        return { valid: false, reason: "Invalid name — use only letters, numbers, spaces, underscores (_), or hyphens (-). Quotes and backslashes are not allowed." };
    }

    const lowerName = trimmed.toLowerCase();
    const isDuplicate = (existingNames.some(existing => existing.toLowerCase() === lowerName) && trimmed !== currentName);
    if (isDuplicate) {
        return { valid: false, reason: "Name already exists" };
    }

    return { valid: true };
}

export {
    clearObject,
    extractLineFromRawText,
    generateUniqueId,
    generateStyleSelector,
    generateFontFamilyString,
    rgbToHex,
    convertToHex,
    removeChildElements,
    stripQuotes,
    decodeHtmlEntities,
    difference,
    checkFileExists,
    getRandomColor,
    cleanAndFlattenCSS,
    parseCssBlock,
    stringifyCssBlock,
    checkNameValidity
};
