// Copyright (c) 2026 Modelware. All rights reserved.
import { QueryMarkdownBlockRenderer } from './renderer.js';
import { appendInlineValue } from './wikilink-utils.js';
export class ListMarkdownBlockRenderer extends QueryMarkdownBlockRenderer {
    canRender(result) {
        return result.status === 'ok'
            && result.kind === 'list'
            && result.format === 'table'
            && !!result.payload;
    }
    render(result) {
        const container = this.createResultContainer(result.status);
        container.classList.add('oml-md-result-plain');
        const payload = result.payload;
        if (!payload || payload.rows.length === 0) {
            container.appendChild(this.createMessageContainer('No results.'));
            return container;
        }
        const stylesheet = compileListStylesheet(result.options);
        const list = document.createElement('ul');
        list.className = 'oml-md-result-list';
        const listContext = { kind: 'list', context: {} };
        for (const rule of stylesheet) {
            if (!matchesListRule(rule, [listContext])) {
                continue;
            }
            if (rule.target === 'marker') {
                continue;
            }
            applyValueStyles(list, rule.style);
        }
        payload.rows.forEach((row, index) => {
            const item = document.createElement('li');
            const valueSpan = document.createElement('span');
            valueSpan.className = 'oml-md-result-list-value';
            appendInlineValue(valueSpan, row[0] ?? '');
            item.appendChild(valueSpan);
            const itemContext = {
                kind: 'item',
                context: {
                    index,
                    value: row[0] ?? '',
                    row: createRowAccessor(payload.columns, row)
                }
            };
            for (const rule of stylesheet) {
                if (!matchesListRule(rule, [itemContext])) {
                    continue;
                }
                if (rule.target === 'marker') {
                    applyMarkerStyles(item, rule.style);
                }
                else {
                    applyValueStyles(valueSpan, rule.style);
                }
            }
            list.appendChild(item);
        });
        container.appendChild(list);
        return container;
    }
}
function compileListStylesheet(options) {
    const rawStylesheet = options?.stylesheet;
    if (!Array.isArray(rawStylesheet)) {
        return [];
    }
    const compiled = [];
    for (const rawRule of rawStylesheet) {
        if (!isRecord(rawRule)) {
            continue;
        }
        const selectors = parseListSelectors(rawRule.selector);
        if (selectors.length === 0) {
            continue;
        }
        const style = normalizeStyle(rawRule.style);
        if (Object.keys(style).length === 0) {
            continue;
        }
        const target = rawRule.target === 'marker' ? 'marker' : 'value';
        compiled.push({ selectors, target, style });
    }
    return compiled;
}
function matchesListRule(rule, contexts) {
    return rule.selectors.some((selector) => {
        const contextEntry = contexts.find((entry) => entry.kind === selector.kind);
        if (!contextEntry) {
            return false;
        }
        return evaluateCondition(selector.condition, contextEntry.context);
    });
}
function applyValueStyles(target, style) {
    for (const [property, cssValue] of Object.entries(style)) {
        target.style.setProperty(property, cssValue);
    }
}
function applyMarkerStyles(listItem, style) {
    for (const [property, cssValue] of Object.entries(style)) {
        const normalized = property.trim().toLowerCase();
        if (normalized === 'color') {
            listItem.style.setProperty('--oml-list-marker-color', cssValue);
            continue;
        }
        if (normalized === 'font-size') {
            listItem.style.setProperty('--oml-list-marker-font-size', cssValue);
            continue;
        }
        if (normalized === 'font-weight') {
            listItem.style.setProperty('--oml-list-marker-font-weight', cssValue);
            continue;
        }
        if (normalized === 'font-style') {
            listItem.style.setProperty('--oml-list-marker-font-style', cssValue);
        }
    }
}
function parseListSelectors(rawSelector) {
    if (typeof rawSelector !== 'string') {
        return [];
    }
    const parts = splitSelectors(rawSelector);
    const selectors = [];
    for (const part of parts) {
        const parsed = parseListSelector(part);
        if (parsed) {
            selectors.push(parsed);
        }
    }
    return selectors;
}
function splitSelectors(rawSelector) {
    const parts = [];
    let current = '';
    let bracketDepth = 0;
    let quote;
    for (let index = 0; index < rawSelector.length; index += 1) {
        const char = rawSelector[index];
        if (quote) {
            current += char;
            if (char === quote && rawSelector[index - 1] !== '\\') {
                quote = undefined;
            }
            continue;
        }
        if (char === '"' || char === "'") {
            quote = char;
            current += char;
            continue;
        }
        if (char === '[') {
            bracketDepth += 1;
            current += char;
            continue;
        }
        if (char === ']' && bracketDepth > 0) {
            bracketDepth -= 1;
            current += char;
            continue;
        }
        if (char === ',' && bracketDepth === 0) {
            parts.push(current.trim());
            current = '';
            continue;
        }
        current += char;
    }
    if (current.trim()) {
        parts.push(current.trim());
    }
    return parts;
}
function parseListSelector(selector) {
    const trimmed = selector.trim();
    if (!trimmed) {
        return undefined;
    }
    const bracketStart = trimmed.indexOf('[');
    if (bracketStart === -1) {
        return toListSelector(trimmed, undefined);
    }
    if (!trimmed.endsWith(']')) {
        return undefined;
    }
    const kind = trimmed.slice(0, bracketStart).trim();
    const condition = trimmed.slice(bracketStart + 1, -1).trim();
    return toListSelector(kind, condition || undefined);
}
function toListSelector(kind, condition) {
    const normalized = kind.trim().toLowerCase();
    if (normalized !== 'list' && normalized !== 'item') {
        return undefined;
    }
    return { kind: normalized, condition };
}
function normalizeStyle(rawStyle) {
    if (!isRecord(rawStyle)) {
        return {};
    }
    const style = {};
    for (const [property, rawValue] of Object.entries(rawStyle)) {
        if (!property.trim()) {
            continue;
        }
        if (rawValue === undefined || rawValue === null) {
            continue;
        }
        style[property] = String(rawValue);
    }
    return style;
}
function createRowAccessor(columns, row) {
    return {
        get: (key) => {
            if (typeof key === 'number' && Number.isInteger(key)) {
                const value = row[key];
                return value === undefined ? undefined : { value };
            }
            if (typeof key === 'string') {
                const index = columns.indexOf(key);
                if (index < 0) {
                    return undefined;
                }
                const value = row[index];
                return value === undefined ? undefined : { value };
            }
            return undefined;
        }
    };
}
function evaluateCondition(condition, context) {
    if (!condition) {
        return true;
    }
    try {
        const scope = Object.assign(Object.create(null), context);
        const keys = Object.keys(scope);
        const values = keys.map((key) => scope[key]);
        // eslint-disable-next-line no-new-func
        const evaluator = new Function(...keys, `"use strict"; return (${condition});`);
        return Boolean(evaluator(...values));
    }
    catch {
        return false;
    }
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
//# sourceMappingURL=list-renderer.js.map